/* eslint-disable max-lines */
/* globals tryTests */
import { use as chaiUse, expect } from 'chai';
import chaiAsPromised from 'chai-as-promised'; // eslint-disable-line import/newline-after-import
chaiUse(chaiAsPromised);

import sinon from 'sinon';
import openpgp from '../initOpenpgp.js';
import util from '../../src/util.js';
import { getPreferredCipherSuite, getPreferredHashAlgo } from '../../src/key';
import KeyID from '../../src/type/keyid.js';

const priv_key_arm2 =
  ['-----BEGIN PGP PRIVATE KEY BLOCK-----',
    'Version: GnuPG v2.0.19 (GNU/Linux)',
    '',
    'lQH+BFJhL04BBADclrUEDDsm0PSZbQ6pml9FpzTyXiyCyDN+rMOsy9J300Oc10kt',
    '/nyBej9vZSRcaW5VpNNj0iA+c1/w2FPf84zNsTzvDmuMaNHFUzky4/vkYuZra//3',
    '+Ri7CF8RawSYQ/4IRbC9zqdBlzniyfQOW7Dp/LYe8eibnDSrmkQem0G0jwARAQAB',
    '/gMDAu7L//czBpE40p1ZqO8K3k7UejemjsQqc7kOqnlDYd1Z6/3NEA/UM30Siipr',
    'KjdIFY5+hp0hcs6EiiNq0PDfm/W2j+7HfrZ5kpeQVxDek4irezYZrl7JS2xezaLv',
    'k0Fv/6fxasnFtjOM6Qbstu67s5Gpl9y06ZxbP3VpT62+Xeibn/swWrfiJjuGEEhM',
    'bgnsMpHtzAz/L8y6KSzViG/05hBaqrvk3/GeEA6nE+o0+0a6r0LYLTemmq6FbaA1',
    'PHo+x7k7oFcBFUUeSzgx78GckuPwqr2mNfeF+IuSRnrlpZl3kcbHASPAOfEkyMXS',
    'sWGE7grCAjbyQyM3OEXTSyqnehvGS/1RdB6kDDxGwgE/QFbwNyEh6K4eaaAThW2j',
    'IEEI0WEnRkPi9fXyxhFsCLSI1XhqTaq7iDNqJTxE+AX2b9ZuZXAxI3Tc/7++vEyL',
    '3p18N/MB2kt1Wb1azmXWL2EKlT1BZ5yDaJuBQ8BhphM3tCRUZXN0IE1jVGVzdGlu',
    'Z3RvbiA8dGVzdEBleGFtcGxlLmNvbT6IuQQTAQIAIwUCUmEvTgIbLwcLCQgHAwIB',
    'BhUIAgkKCwQWAgMBAh4BAheAAAoJEEpjYTpNbkCUMAwD+gIK08qpEZSVas9qW+Ok',
    '32wzNkwxe6PQgZwcyBqMQYZUcKagC8+89pMQQ5sKUGvpIgat42Tf1KLGPcvG4cDA',
    'JZ6w2PYz9YHQqPh9LA+PAnV8m25TcGmKcKgvFUqQ3U53X/Y9sBP8HooRqfwwHcv9',
    'pMgQmojmNbI4VHydRqIBePawnQH+BFJhL04BBADpH8+0EVolpPiOrXTKoBKTiyrB',
    'UyxzodyJ8zmVJ3HMTEU/vidpQwzISwoc/ndDFMXQauq6xqBCD9m2BPQI3UdQzXnb',
    'LsAI52nWCIqOkzM5NAKWoKhyXK9Y4UH4v9LAYQgl/stIISvCgG4mJ8lzzEBWvRdf',
    'Qm2Ghb64/3V5NDdemwARAQAB/gMDAu7L//czBpE40iPcpLzL7GwBbWFhSWgSLy53',
    'Md99Kxw3cApWCok2E8R9/4VS0490xKZIa5y2I/K8thVhqk96Z8Kbt7MRMC1WLHgC',
    'qJvkeQCI6PrFM0PUIPLHAQtDJYKtaLXxYuexcAdKzZj3FHdtLNWCooK6n3vJlL1c',
    'WjZcHJ1PH7USlj1jup4XfxsbziuysRUSyXkjn92GZLm+64vCIiwhqAYoizF2NHHG',
    'hRTN4gQzxrxgkeVchl+ag7DkQUDANIIVI+A63JeLJgWJiH1fbYlwESByHW+zBFNt',
    'qStjfIOhjrfNIc3RvsggbDdWQLcbxmLZj4sB0ydPSgRKoaUdRHJY0S4vp9ouKOtl',
    '2au/P1BP3bhD0fDXl91oeheYth+MSmsJFDg/vZJzCJhFaQ9dp+2EnjN5auNCNbaI',
    'beFJRHFf9cha8p3hh+AK54NRCT++B2MXYf+TPwqX88jYMBv8kk8vYUgo8128r1zQ',
    'EzjviQE9BBgBAgAJBQJSYS9OAhsuAKgJEEpjYTpNbkCUnSAEGQECAAYFAlJhL04A',
    'CgkQ4IT3RGwgLJe6ogQA2aaJEIBIXtgrs+8WSJ4k3DN4rRXcXaUZf667pjdD9nF2',
    '3BzjFH6Z78JIGaxRHJdM7b05aE8YuzM8f3NIlT0F0OLq/TI2muYU9f/U2DQBuf+w',
    'KTB62+PELVgi9MsXC1Qv/u/o1LZtmmxTFFOD35xKsxZZI2OJj2pQpqObW27M8Nlc',
    'BQQAw2YA3fFc38qPK+PY4rZyTRdbvjyyX+1zeqIo8wn7QCQwXs+OGaH2fGoT35AI',
    'SXuqKcWqoEuO7OBSEFThCXBfUYMC01OrqKEswPm/V3zZkLu01q12UMwZach28QwK',
    '/YZly4ioND2tdazj17u2rU2dwtiHPe1iMqGgVMoQirfLc+k=',
    '=lw5e',
    '-----END PGP PRIVATE KEY BLOCK-----'].join('\n');

const pub_key_arm2 =
  ['-----BEGIN PGP PUBLIC KEY BLOCK-----',
    'Version: GnuPG v2.0.19 (GNU/Linux)',
    '',
    'mI0EUmEvTgEEANyWtQQMOybQ9JltDqmaX0WnNPJeLILIM36sw6zL0nfTQ5zXSS3+',
    'fIF6P29lJFxpblWk02PSID5zX/DYU9/zjM2xPO8Oa4xo0cVTOTLj++Ri5mtr//f5',
    'GLsIXxFrBJhD/ghFsL3Op0GXOeLJ9A5bsOn8th7x6JucNKuaRB6bQbSPABEBAAG0',
    'JFRlc3QgTWNUZXN0aW5ndG9uIDx0ZXN0QGV4YW1wbGUuY29tPoi5BBMBAgAjBQJS',
    'YS9OAhsvBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQSmNhOk1uQJQwDAP6',
    'AgrTyqkRlJVqz2pb46TfbDM2TDF7o9CBnBzIGoxBhlRwpqALz7z2kxBDmwpQa+ki',
    'Bq3jZN/UosY9y8bhwMAlnrDY9jP1gdCo+H0sD48CdXybblNwaYpwqC8VSpDdTndf',
    '9j2wE/weihGp/DAdy/2kyBCaiOY1sjhUfJ1GogF49rC4jQRSYS9OAQQA6R/PtBFa',
    'JaT4jq10yqASk4sqwVMsc6HcifM5lSdxzExFP74naUMMyEsKHP53QxTF0Grqusag',
    'Qg/ZtgT0CN1HUM152y7ACOdp1giKjpMzOTQClqCoclyvWOFB+L/SwGEIJf7LSCEr',
    'woBuJifJc8xAVr0XX0JthoW+uP91eTQ3XpsAEQEAAYkBPQQYAQIACQUCUmEvTgIb',
    'LgCoCRBKY2E6TW5AlJ0gBBkBAgAGBQJSYS9OAAoJEOCE90RsICyXuqIEANmmiRCA',
    'SF7YK7PvFkieJNwzeK0V3F2lGX+uu6Y3Q/Zxdtwc4xR+me/CSBmsURyXTO29OWhP',
    'GLszPH9zSJU9BdDi6v0yNprmFPX/1Ng0Abn/sCkwetvjxC1YIvTLFwtUL/7v6NS2',
    'bZpsUxRTg9+cSrMWWSNjiY9qUKajm1tuzPDZXAUEAMNmAN3xXN/Kjyvj2OK2ck0X',
    'W748sl/tc3qiKPMJ+0AkMF7Pjhmh9nxqE9+QCEl7qinFqqBLjuzgUhBU4QlwX1GD',
    'AtNTq6ihLMD5v1d82ZC7tNatdlDMGWnIdvEMCv2GZcuIqDQ9rXWs49e7tq1NncLY',
    'hz3tYjKhoFTKEIq3y3Pp',
    '=h/aX',
    '-----END PGP PUBLIC KEY BLOCK-----'].join('\n');

const pub_key_arm4 = `-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG 2.1.15 (GNU/Linux)

mI0EWpoNLAEEAMoO8dfnLvvCze1hjWcr8t1fMdndFQc1fAM7dm6sbqrdlaAz+Dab
zF3F9UhIOCcABRm+QHyZlgEsoQpHF/7sWflUK1FpoxdORINtIDilukUkMZ0NnIaD
+8pRutdSczPNFvSImSzZNCyLzvDCGMO3+Xeaa6pViSPEeBwhXWJUuHYtABEBAAG0
IkpvZSBVc2VyIDxqb2UudXNlckBwcm90b25tYWlsLmNvbT6ItwQTAQgAIQUCWpoN
LAIbAwULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgAAKCRBYtrN4WUnCtoUjBACi6qVb
noQJ1aOaOyoBZscDIO5XZHZK4L9V9uJJhD9v1qRF5s0PRiG969EwFlvjqIlLiRej
KSxvE/1rcym4GwBUndku1fMM+weTWHNtRn9+BPzN/4eKZbUbY3fHtlk+Lde3N+CZ
vrGKS/ICtbtuAfZL0LdzzqnNuBUXlO6EpG5C3riNBFqaDSwBBADDURzGkpTn/FTT
xHyheai+zTOUmy7N1ViCRPkErIeD606tZf/sKqAnEChfECeZJReYydN1B3O8QOyI
Ly/rH0DS2bt/6juhknPVGHPUAyNxHmiHYXTUgGPEX1QfusjzBcfIk6vHjYBiRm/I
u9iwrzCwypA4dWDZSTZuFrVsf4n+twARAQABiJ8EGAEIAAkFAlqaDSwCGwwACgkQ
WLazeFlJwrZQEAQAuUrp9Qp76CnKqUsUjcVxq7DJBi/lewyGGYSVAFt6/0Xyg/8Y
TEa/c4Dri/HMOtrfbgjp/doIVaZLOXZYfqRcpy3z0M6BierOPB3D+fdaTfd7gIrQ
nGHIp2NmbJZnYgl8Ps23qF+LKTa1eE+AmMQYzUHSGuka2lp6OglwWzg/dEw=
=/vbH
-----END PGP PUBLIC KEY BLOCK-----`;

/* const priv_key_arm4 = `-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: GnuPG 2.1.15 (GNU/Linux)

lQIGBFqaDSwBBADKDvHX5y77ws3tYY1nK/LdXzHZ3RUHNXwDO3ZurG6q3ZWgM/g2
m8xdxfVISDgnAAUZvkB8mZYBLKEKRxf+7Fn5VCtRaaMXTkSDbSA4pbpFJDGdDZyG
g/vKUbrXUnMzzRb0iJks2TQsi87wwhjDt/l3mmuqVYkjxHgcIV1iVLh2LQARAQAB
/gcDAoZ8RULY7umS4fVGPmTuETCnOOTGancXT5r7chKyfFXlyVU4ULvTdLwdFtqx
Vl9tNyED31nIiRP1CTmZLeaVScNGfVLjo8nvpMZUVopw5UdaFADeVTpwVdtp7ru+
IgH4ynrRMgMGh7/dgBzIP8WN4w8uBPK5G4bS34NNiREkVoZ3oh4dA/6aeYfW7lVV
cYRl2F7++AGfqS+FpLsE8KjFU2z8POJjWMN1nYKwjNa+beEO0BFYdUFvMzU7eUHA
/G0xWAhYvNyuJHE4imgYmCy1OZeawc9h8YGeaQJCh2NTVzaD9HRu0xmz93bNF19q
bfUZJC7mC6WzKsRXHX0JmzH+9DShUqGnkRl5fMo2UhQMpSxsMT4dU/Ji4q+t96oy
K6g3DMJr5OtZML3XKxGmdy0CgepkG1aikrC9qLfBgxjqi+uTewcbrS9lAOfrZg4N
jwt1FLEK8gu7aOeczdW/pFOHOCrX1DnpF81JKJ1a7hz5JRP1m+ffqwm0IkpvZSBV
c2VyIDxqb2UudXNlckBwcm90b25tYWlsLmNvbT6ItwQTAQgAIQUCWpoNLAIbAwUL
CQgHAgYVCAkKCwIEFgIDAQIeAQIXgAAKCRBYtrN4WUnCtoUjBACi6qVbnoQJ1aOa
OyoBZscDIO5XZHZK4L9V9uJJhD9v1qRF5s0PRiG969EwFlvjqIlLiRejKSxvE/1r
cym4GwBUndku1fMM+weTWHNtRn9+BPzN/4eKZbUbY3fHtlk+Lde3N+CZvrGKS/IC
tbtuAfZL0LdzzqnNuBUXlO6EpG5C3p0CBgRamg0sAQQAw1EcxpKU5/xU08R8oXmo
vs0zlJsuzdVYgkT5BKyHg+tOrWX/7CqgJxAoXxAnmSUXmMnTdQdzvEDsiC8v6x9A
0tm7f+o7oZJz1Rhz1AMjcR5oh2F01IBjxF9UH7rI8wXHyJOrx42AYkZvyLvYsK8w
sMqQOHVg2Uk2bha1bH+J/rcAEQEAAf4HAwLwNvRIoBFS3OHTIYirkr4sHzSkWFJx
xDPozovXgCq7BoCXDMaSIQLwZqEfb+SabYtk7nLSnG2Y2mgwb9swZuBZEWuQjZk7
lX1MvuZ0Ih2QdQSMEJk8sEsMoBGHHdHh/MZO4a27+5B9OceDfnEZZcGSOweUuu1n
IlgWcgrM40q4S3Mt39FXFgdJWnpd93hAokKDHklUGMdMLw/02dGVRkJmvUp9qdhe
c2njq9HSeYwqbY2rYgcNsF2ZcCLt9UXA2dOG4X2c2mPfjKuTRZUPxNKh6JfL3mlu
rBdd/z8gQHoKObyaarVwN3HAbtP0+6Z8a9/wDYj1K9ZCoHuEtKq1qq5J2Ec8+Yzl
K0Zlcs760LiYUr69CninMrnbDNnAhrYAcyJS42viUADPv9g+CBbyanB4KyE4UNrZ
BCB296lOEW4v1IZVNrNvqrbka3/p0qqBJiFTh7eT3zXpRNArFZDmLCUEEm53qT1a
PO/MyYUGTTMRAzTmNTiPiJ8EGAEIAAkFAlqaDSwCGwwACgkQWLazeFlJwrZQEAQA
uUrp9Qp76CnKqUsUjcVxq7DJBi/lewyGGYSVAFt6/0Xyg/8YTEa/c4Dri/HMOtrf
bgjp/doIVaZLOXZYfqRcpy3z0M6BierOPB3D+fdaTfd7gIrQnGHIp2NmbJZnYgl8
Ps23qF+LKTa1eE+AmMQYzUHSGuka2lp6OglwWzg/dEw=
=mr3M
-----END PGP PRIVATE KEY BLOCK-----`; */

const revocation_certificate_arm4 = `-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG 2.1.15 (GNU/Linux)
Comment: This is a revocation certificate

iJ8EIAEIAAkFAlqaDT0CHQAACgkQWLazeFlJwrbOaAP/V38FhBrUy4XYgt8ZX22G
ov6IFDNoyRKafSuz7Rg+8K8cf+0MAsSi52ueKfsbPxQ+I1vPeaEuEYbwTjtbvM+M
vZcX+VNYdsc1iZeNaT4ayA+2LrCN/xgFj0nrExHqcZAjgBZ9pvKghAqdK4Zb2Ghb
7chPiLLNWJCMtL4bo7a1X84=
=HcWg
-----END PGP PUBLIC KEY BLOCK-----`;

const revoked_key_arm4 = `-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG 2.1.15 (GNU/Linux)

mI0EWpoNLAEEAMoO8dfnLvvCze1hjWcr8t1fMdndFQc1fAM7dm6sbqrdlaAz+Dab
zF3F9UhIOCcABRm+QHyZlgEsoQpHF/7sWflUK1FpoxdORINtIDilukUkMZ0NnIaD
+8pRutdSczPNFvSImSzZNCyLzvDCGMO3+Xeaa6pViSPEeBwhXWJUuHYtABEBAAGI
nwQgAQgACQUCWpoNPQIdAAAKCRBYtrN4WUnCts5oA/9XfwWEGtTLhdiC3xlfbYai
/ogUM2jJEpp9K7PtGD7wrxx/7QwCxKLna54p+xs/FD4jW895oS4RhvBOO1u8z4y9
lxf5U1h2xzWJl41pPhrID7YusI3/GAWPSesTEepxkCOAFn2m8qCECp0rhlvYaFvt
yE+Iss1YkIy0vhujtrVfzrQiSm9lIFVzZXIgPGpvZS51c2VyQHByb3Rvbm1haWwu
Y29tPoi3BBMBCAAhBQJamg0sAhsDBQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJ
EFi2s3hZScK2hSMEAKLqpVuehAnVo5o7KgFmxwMg7ldkdkrgv1X24kmEP2/WpEXm
zQ9GIb3r0TAWW+OoiUuJF6MpLG8T/WtzKbgbAFSd2S7V8wz7B5NYc21Gf34E/M3/
h4pltRtjd8e2WT4t17c34Jm+sYpL8gK1u24B9kvQt3POqc24FReU7oSkbkLeuI0E
WpoNLAEEAMNRHMaSlOf8VNPEfKF5qL7NM5SbLs3VWIJE+QSsh4PrTq1l/+wqoCcQ
KF8QJ5klF5jJ03UHc7xA7IgvL+sfQNLZu3/qO6GSc9UYc9QDI3EeaIdhdNSAY8Rf
VB+6yPMFx8iTq8eNgGJGb8i72LCvMLDKkDh1YNlJNm4WtWx/if63ABEBAAGInwQY
AQgACQUCWpoNLAIbDAAKCRBYtrN4WUnCtlAQBAC5Sun1CnvoKcqpSxSNxXGrsMkG
L+V7DIYZhJUAW3r/RfKD/xhMRr9zgOuL8cw62t9uCOn92ghVpks5dlh+pFynLfPQ
zoGJ6s48HcP591pN93uAitCcYcinY2ZslmdiCXw+zbeoX4spNrV4T4CYxBjNQdIa
6RraWno6CXBbOD90TA==
=8d2d
-----END PGP PUBLIC KEY BLOCK-----`;

const twoKeys = `-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2.0.19 (GNU/Linux)

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
PepQmgsu
=w6wd
-----END PGP PUBLIC KEY BLOCK-----`;

const pub_revoked_subkeys =
  ['-----BEGIN PGP PUBLIC KEY BLOCK-----',
    'Version: GnuPG v2.0.19 (GNU/Linux)',
    '',
    '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',
    'pMiJM+NJAQ==',
    '=ok+o',
    '-----END PGP PUBLIC KEY BLOCK-----'].join('\n');

const pub_revoked_with_cert =
  ['-----BEGIN PGP PUBLIC KEY BLOCK-----',
    'Comment: GPGTools - https://gpgtools.org',
    '',
    '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',
    'onCOcv4DKguN2w==',
    '=OqO3',
    '-----END PGP PUBLIC KEY BLOCK-----'].join('\n');

const pub_sig_test =
  ['-----BEGIN PGP PUBLIC KEY BLOCK-----',
    'Version: GnuPG v2.0.19 (GNU/Linux)',
    '',
    'mQENBFKgqXUBCADC4c6sSBnBU+15Y32/a8IXqO2WxKxSHj7I5hv1OdSTmSZes7nZ',
    '5V96qsk0k5/ka3C2In+GfTKfuAJ0oVkTZVi5tHP9D+PcZngrIFX56OZ2P5PtTU7U',
    'jh0C78JwCVnv6Eg57JnIMwdbL3ZLqmogLhw5q15Hie5btCIQnuuKfrwxnsox4i3q',
    'dYCHYB1HBGzpvflS07r3Y3IRFJaP8hUhx7PsvpD1s+9DU8AuMNZTXAqRI/bms5hC',
    'BpVejXLj/vlNeQil99MoI7s14L+dHogYuUOUbsXim5EyIFfF/1v+o5l0wmueWrE8',
    'mYQfj5ZvURlGVFah9ECaW9/ResCyJ1Yh975xABEBAAG0I1NpZ25hdHVyZSBUZXN0',
    'IDxzaWduYXR1cmVAdGVzdC5jb20+iQE8BBMBAgAmAhsDBwsJCAcDAgEGFQgCCQoL',
    'BBYCAwECHgECF4AFAlKgq80CGQEACgkQwHbmNNMrSY3KKQf/UGnuc6LbVyhkFQKo',
    'USTVDFg/42CVmIGOG+aZBo0VZuzNYARwDKyoZ5okKqZi5VSfdDaBXuW4VIYepvux',
    'AV8eJV6GIsLRv/wJcKPABIXDIK1tdNetiYbd+2/Fb2/YqAX5wOKIxd3Ggzyx5X4F',
    'WhA6fIBIXyShUWoadkX7S87z5hryhII9281rW2mOsLC5fy/SUQUWM1YmsZ1owvY9',
    'q6W8xRnHDmY+Ko91xex7fikDLBofsWbTUc0/O/1o9miIZfp2nXLKQus2H1WdZVOe',
    'H9zFiy54x7+zTov94SJE3xXppoQnIpeOTlFjTP2mjxm0VW1Dn9lGE3IFgWolpNPy',
    'Rv6dnLQdU2Vjb25kIFVzZXIgPHNlY29uZEB1c2VyLmNvbT6IowQwAQIADQUCUrF1',
    'hwYdIEh1cnoACgkQSmNhOk1uQJRVeQP9GQoLvan5FMYcPPY4a9dNlkvtheRXcoif',
    'oYdQoEyy9zAFCqmg2pC6RrHaMwNINw534JDh2vgWQ0MU3ktMJjSvGBBHayQc6ov8',
    'i4I6rUPBlYoSDKyFnhCCXWF56bHMGyEGJhcQLv1hrGPVv6PTKj3hyR+2n50Impwo',
    'UrlFIwYZNyWJAS8EMAECABkFAlKgqqYSHSBUZXN0aW5nIHB1cnBvc2VzAAoJEMB2',
    '5jTTK0mNvKAH/Rgu+I12Fb7S8axNwzp5m/jl1iscYbjgOrdUEI7bc2yo0KhGwYOV',
    'U3Zj68Ogj6gkLkVwfhvJYZJgfYBG7nTxkC5/MTABQrAI5ZX89Hh9y0tLh2wKr5iK',
    'MH6Mi9xxJmVJ+IiAKx/02f+sKWh4tv3TFNNxnp24LPHWz7RMd/o4m8itmzQxFmaZ',
    'yEPd/CD6hYqSMP5Y7zMN4gTB+tHsawB9PWkrF/dW8bk3PtZanDlBMUSVrPH15bIZ',
    'lFO1NKEN39WagmNe5wezKxWmHBcuISQHxCIX3Hf4dYyexndX25fMphF93YgQnNE+',
    'zQeBJyNBKRpMXzGndELo5KFaA1YyC07GKKyJATkEEwECACMFAlKgqeYCGwMHCwkI',
    'BwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRDAduY00ytJjagNCACGQMQPl6foIVcz',
    'OzLf8npGihIjiIYARQz4+yg6ze9TG2hjIpWLiwGNJ0uEG22cFiN7OeFnUADFi131',
    'oEtZzIXcBd0A1S87ooH+86YjpvLj5PMlviVKGsGmdqtWpQN5fII8brydNLwSHlLV',
    '+JolvyMlA2Ao/sePopR0aSKIPfD108YIIiZztE4pHgDzE5G66zAw3zWn/dzLuGln',
    'Mp4nrY8Rxb68MaZFhVq0A5QFzlOjQ/iDJWrPM6vy/U8TQxmaYGMjcEyEEil+3+OJ',
    'OFqfB4byISOIxL9LqFVRndbgOw7ICi+qE2e7+9G2koCtEkjpPg3ZCF4mfZiaLT9p',
    'QhoFS4yxiJwEEAECAAYFAlKgqhYACgkQSmNhOk1uQJSJ0gP9F5RRwGBbXD4Mg4gq',
    'wcQYrzw9ZAapLKZ2vuco6gHknQAM1YuaOpKQu1rd6eFzKE4M11CLmoS/CalDhg9f',
    'aN6fvTZG7lbUnSZKl/tgvG7qeneA919/b1RtMNDkHmRxvHysiyDYmkJYlmZlwXZB',
    '5FBoRvv5b2oXfWLLEcNvUvbetuC5AQ0EUqCpdQEIAOMvycVLkIKm9EMbxFqGc019',
    'yjCB3xiK+hF0PwdfWBXF8KskJ4hfybd19LdO6EGnKfAVGaeVEt6RtUJMsgfhqAhE',
    'BwaeHLLfjXjd7PetBdzybh0u2kfaGDBQshdEuLcfqTqp4+R+ha1epdXAPDP+lb9E',
    '5OXIOU2EWLSY+62fyGw3kvUSYNQKufDoKuq5vzltW1uYVq3aeA7e/yTqEoWSoRGo',
    '25f/xaY6u6sYIyLpkZ6IX1n1BzLirfJSkJ8svNX+hNihCDshKJUDoMwAPcRdICkr',
    'vFbrO3k24OylQA6dpQqHUWD9kVu8sEZH/eiHZ5YBo/hgwNH7UMaFSBAYQZrSZjcA',
    'EQEAAYkBHwQoAQIACQUCUqCrcgIdAwAKCRDAduY00ytJjeO9B/9O/A6idEMy6cEG',
    'PAYv0U/SJW0RcM54/Ptryg3jiros+qkLQD+Hp2q/xxpXKFPByGWkkGZnNIIxaA1j',
    'SPvOJXrK728b/OXKB3IaMknKTB7gLGH4oA9/dmzHgbeqNWXYok5GSwPxLSUoeIrZ',
    'j+6DkUz2ebDx1FO797eibeL1Dn15iyWh/l3QMT+1fLjJyVDnEtNhZibMlDPohVuS',
    'suJfoKbQJkT6mRy4nDWsPLzFOt3VreJKXo9MMrrHV44XeOKo5nqCK3KsfCoeoqft',
    'G7e/NP4DgcfkgNrU/XnBmR9ZVn9/o3EbDENniOVlNH2JaSQskspv5fv7k6dRWn4Q',
    'NRhN5uMWiQEfBBgBAgAJBQJSoKl1AhsMAAoJEMB25jTTK0mNgaEIAKBkMGTSexox',
    'zy6EWtSR+XfA+LxXjhwOgJWrRKvLUqssGbhQNRfY3gy7dEGiSKdnIV+d/xSLgm7i',
    'zAyE4SjmDDOFRfxpyEsxhw2738OyEenEvO70A2J6RLj91Rfg9+vhT7WWyxBKdU1b',
    'zM2ZORHCBUmbqjYAiLUbz0E589YwJR3a7osjCC8Lstf2C62ttAAAcKks2+wt4kUQ',
    'Zm7WAUi1kG26VvOXVg9Tnj00mnBWmWlLPG7Qjudf2RBMJ/S8gg9OZWpBN29NEl6X',
    'SU+DbbDHw3G97gRNE7QcHZPGyRtjbKv3nV2mJ8DMKrTzLuPUUcFqd7AlpdrFeDx/',
    '8YM3DBS79eW5Ay4EUqCq0hEIAMIgqJsi3uTPzJw4b4c1Oue+O98jWaacrk7M57+y',
    'Ol209yRUDyLgojs8ZmEZWdvjBG1hr15FIYI4BmusVXHCokVDGv8KNP4pvbf5wljM',
    '2KG1FAxvxZ38/VXTDVH8dOERTf8JPLKlSLbF6rNqfePIL/1wto47b6oRCdawIC25',
    'ft6XX18WlE+dgIefbYcmc0BOgHTHf8YY04IIg67904/RRE6yAWS42Ibx4h1J/haP',
    '95SdthKg5J4HQ2lhudC2NJS3p+QBEieavSFuYTXgJwEeLs6gobwpZ7B0IWqAFCYH',
    'rUOxA35MIg39TfZ4VAC+QZRjoDlp+NAM6tP9HfzsiTi5IecBAOEsOESNYr4ifBkw',
    'StjpU6GuGydZf8MP/Ab/EHDAgYTlB/9VLpplMKMVCJLfYIOxEPkhYCfu30kxzsAL',
    'dLmatluP33Zxv0YMnin6lY4Wii0G56ZovbuKDnGR1JcJT4Rr6ZUdd5dZzGqaP7Aj',
    'J/thLQbIJdC1cGntd2V4lyMSly03ENXxYklzWm7S7xgS+uYsE36s1nctytBqxJYl',
    '8e/7y+Zg4DxgrA2RM9+5R5neciiPGJIx16tBjOq/CM+R2d2+998YN7rKLxZ3w12t',
    'RXHdGt2DZBVkH7bWxy8/2nTxwRmMiEcmeHfOsMz8BiEdgAU+E8YvuIYb2hL2Vdly',
    'ie9boAnoy0fvVMOpcexw/DQHQcPba5OlfTQJwhTxnfaVd8jaxxJmCAC3PljfH9+/',
    'MZrI2ApzC/xTP64t1ERJ7KP50eu53D+w2IpBOLJwnxMIxjtePRSdbF/0EEEL/0jF',
    'GPSGNEw95/QZAyvbhkCTHuo2Sz3f0M2hCCzReo+t+et13h/7nQhEeNEJtOFFu/t+',
    'nX9BrqNLCjH/6TCpQOkiZC3JQGzJxLU15P0LT+/20Rd8ysym0kPg2SrJCnyOrWwZ',
    'wj+1hEHR9pfNtPIZx2LodtRF//Qo9KMSv9G6Tw3a60x7+18siHxTO9wzOxJxRnqN',
    'LgguiQYq//N6LxF1MeQSxxmNr6kNalafp+pwRwNV4G2L7QWPYn3Axe5oEbjKfnoF',
    'pwhalEs4PCnNiQGFBBgBAgAPBQJSoKrSAhsCBQkAAVGAAGoJEMB25jTTK0mNXyAE',
    'GREIAAYFAlKgqtIACgkQqxSB4x5Bj2igHQD+JYra3ESBrVwurLq4n8mm4bq5Wujm',
    'Da5k6Vf7F7ytbDAA/jb47AhgcDXQRcMw0ElTap5AP/JgtuglW/fO4cJxJfa8Yf0H',
    '/i95k6w/MOn5CIwgpZyHc/F4bAVyaZmZ8gAT4lhn03ZDehFNrGJ0IhQH/QfqqNSp',
    'NqG8h7GQIH6ovJlLIcolszIL3khI7LhMsIS6Yi8xpPPB9QcqNmjYkuYAtPE2KyL+',
    '2yBt+f4AJ/VFnBygcUf+AC6YxBS3cYclGKUAE9j6StRGj3kPNJPF7M5dZi+1+1Tu',
    'yJ5ucX3iq+3GKLq98Lv7SPUxIqkxuZbkZIoX99Wqz8of9BUV2wTDvVXB7TEPC5Ho',
    '1y9Mb82aDrqPCq3DXvw5nz3EwxYqIXoKvLW5zsScBg9N3gmMeukXr2FCREKP5oht',
    'yeSTTh8ZnzRiwuUH1t90E7w=',
    '=e8xo',
    '-----END PGP PUBLIC KEY BLOCK-----'].join('\n');

const priv_key_rsa =
  ['-----BEGIN PGP PRIVATE KEY BLOCK-----',
    'Version: GnuPG v2.0.19 (GNU/Linux)',
    '',
    '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',
    '=lw5e',
    '-----END PGP PRIVATE KEY BLOCK-----'].join('\n');

const user_attr_key =
  ['-----BEGIN PGP PUBLIC KEY BLOCK-----',
    'Version: GnuPG v2.0.22 (GNU/Linux)',
    '',
    'mI0EUmEvTgEEANyWtQQMOybQ9JltDqmaX0WnNPJeLILIM36sw6zL0nfTQ5zXSS3+',
    'fIF6P29lJFxpblWk02PSID5zX/DYU9/zjM2xPO8Oa4xo0cVTOTLj++Ri5mtr//f5',
    'GLsIXxFrBJhD/ghFsL3Op0GXOeLJ9A5bsOn8th7x6JucNKuaRB6bQbSPABEBAAG0',
    'JFRlc3QgTWNUZXN0aW5ndG9uIDx0ZXN0QGV4YW1wbGUuY29tPoi5BBMBAgAjBQJS',
    'YS9OAhsvBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQSmNhOk1uQJQwDAP6',
    'AgrTyqkRlJVqz2pb46TfbDM2TDF7o9CBnBzIGoxBhlRwpqALz7z2kxBDmwpQa+ki',
    'Bq3jZN/UosY9y8bhwMAlnrDY9jP1gdCo+H0sD48CdXybblNwaYpwqC8VSpDdTndf',
    '9j2wE/weihGp/DAdy/2kyBCaiOY1sjhUfJ1GogF49rDRwc7BzAEQAAEBAAAAAAAA',
    'AAAAAAAA/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQN',
    'DAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/',
    '2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy',
    'MjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAAFABQDASIAAhEBAxEB/8QAHwAAAQUB',
    'AQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQID',
    'AAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0',
    'NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKT',
    'lJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl',
    '5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL',
    '/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHB',
    'CSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpj',
    'ZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3',
    'uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIR',
    'AxEAPwD3+iiigAooooA//9mIuQQTAQIAIwUCUzxDqQIbLwcLCQgHAwIBBhUIAgkK',
    'CwQWAgMBAh4BAheAAAoJEEpjYTpNbkCU9PEEAKMMaXjhGdgDISBXAAEVXL6MB3x1',
    'd/7zBdnUljh1gM34TSKvbeZf7h/1DNgLbJFfSF3KiLViiqRVOumIkjwNIMZPqYtu',
    'WoEcElY50mvTETzOKemCt1GYI0GhOY2uZOVRtQLrkX0CB9r5hEQalkrnjNKlbghj',
    'LfOYu1uARF16cZUWuI0EUmEvTgEEAOkfz7QRWiWk+I6tdMqgEpOLKsFTLHOh3Inz',
    'OZUnccxMRT++J2lDDMhLChz+d0MUxdBq6rrGoEIP2bYE9AjdR1DNedsuwAjnadYI',
    'io6TMzk0ApagqHJcr1jhQfi/0sBhCCX+y0ghK8KAbiYnyXPMQFa9F19CbYaFvrj/',
    'dXk0N16bABEBAAGJAT0EGAECAAkFAlJhL04CGy4AqAkQSmNhOk1uQJSdIAQZAQIA',
    'BgUCUmEvTgAKCRDghPdEbCAsl7qiBADZpokQgEhe2Cuz7xZIniTcM3itFdxdpRl/',
    'rrumN0P2cXbcHOMUfpnvwkgZrFEcl0ztvTloTxi7Mzx/c0iVPQXQ4ur9Mjaa5hT1',
    '/9TYNAG5/7ApMHrb48QtWCL0yxcLVC/+7+jUtm2abFMUU4PfnEqzFlkjY4mPalCm',
    'o5tbbszw2VwFBADDZgDd8Vzfyo8r49jitnJNF1u+PLJf7XN6oijzCftAJDBez44Z',
    'ofZ8ahPfkAhJe6opxaqgS47s4FIQVOEJcF9RgwLTU6uooSzA+b9XfNmQu7TWrXZQ',
    'zBlpyHbxDAr9hmXLiKg0Pa11rOPXu7atTZ3C2Ic97WIyoaBUyhCKt8tz6Q==',
    '=MVfN',
    '-----END PGP PUBLIC KEY BLOCK-----'].join('\n');

const pgp_desktop_pub =
  ['-----BEGIN PGP PUBLIC KEY BLOCK-----',
    'Version: Encryption Desktop 10.3.0 (Build 9307)',
    '',
    'mQENBFNjoowBCACeKvpQnv8wN3UdDVrZN//Bh/Dtq60hbZ3ObfTbNVBQ0DLD6jWA',
    'lKgwgSa3GLr0a3qrc30CRq0hRIjrFMrg4aPu5sRiZYP90B1cUGf08F2by8f+as2b',
    'BOBzRkcxH/ZmBZPU0pkRoOnkMvoT+YVt2MxzaJRBKM1dgcPXTHvZ52j7V0uEJvs8',
    's/H8DJq6MtgYqoS1zt/+eqUSDCcsVJBsEl7o7qU2d9i074hiBouM2B2mimvBKFIn',
    'W2kmG6fSryNSLaUMwvOTEC/esVNlgvSBfhu82Gic8Rwc+g0cHUnAESChxz/jE0P6',
    'INt2IpBZKeuXCY97tQmce3R4GOc/r3FNBBa3ABEBAAG0HVBHUCBEZXNrdG9wIDEw',
    'LjMgPHBncEBzeW0uZGU+iQFyBBABAgBcBQJTY6KMMBSAAAAAACAAB3ByZWZlcnJl',
    'ZC1lbWFpbC1lbmNvZGluZ0BwZ3AuY29tcGdwbWltZQgLCQgHAwIBCgIZAQUbAwAA',
    'AAUWAAMCAQUeAQAAAAYVCAkKAwIACgkQjhjogWc7SuswzggAhxyEqLPiKTJdQOCj',
    'ewGX/2gyY+oreHZWVqoDU8J0AO3Ppnpv4mcyaKCqAteBzLtDj1KPxqCBF0mpYn9H',
    '4o6qPTPlOFm83tmw8O5bLeNltDjElt93sNaHtWxKWjZReDbq4ZmwbjOoYt6ms1Tm',
    'azkVeEuSTSbDPknSaNh1a9ew1gytH5MWQwovqNxU0AgAKKdspXltssCbLux7gFdI',
    'nzOcRPuCHkCfy4C97qFlwZ2Tb2mDgwZYvACfvU7L5BY68WNnq0GKP5eZzM/Ge0xd',
    'NU8oSSzQ2E5A6clW8Y4xUymhwcpG2CzfbFpA/dVobM4wplD5BPkyJsgWIgnRO9Lo',
    'VF83+7kBDQRTY6KNAQgA6tnPjznr7HHcoEFXNRC+LEkDOLAm5kTU9MY+2joJyHG7',
    'XmEAhPRt4Cp5Fq79sXPvGZ6tQnD8NVvqc3+91ThTLLKCIRdLOunIGIEJdCr7gN49',
    'kgDYisWxt7QQIsv7Q0SqbGJa7F/jPj5EDf36XJlACJy1yfP6KI6NunffLa23BUU0',
    't0S/TWqq4185nQczJ1JnZItyyBIyIWXrNtz56B/mIDvIU56SxxpsrcYctAT68vW0',
    'njyQ7XRNIzsmvn4o+H9YHnSz3VdXeJaXd7TdU+WLT2lbgzF5BvDN3AlJI8jiONfu',
    '0rW9oBmHsQdjDcOlWdExsCx5Lz7+La7EK/mX0rUVeQARAQABiQJBBBgBAgErBQJT',
    'Y6KPBRsMAAAAwF0gBBkBCAAGBQJTY6KOAAoJED0FhXx5gwvfTzoH/3j1tYLvkjM+',
    'XghFCzRWDKB7qMzY1kRFV2TNQALnnu1sdUOrs4bQ3w2/viMp2uMqAyU/2WK1CDum',
    'CA6+DYV1vFPsMX/l+efjK8g2b/3RJx/9oc/hUEphWbzY5WCawGodVFa+Yd6nkpBy',
    'oksEIR1I5K03ki5Bk45Bp4vQIoZvnQeTlmLQTxdaEPTcbTMQXHZPhpq65n7NFiie',
    'mRrruRDbl3gzJOAsRtM/2TVFWdkvmANx8S+OTsQGxSCP6ZFQed6K0wj9/HZzG5Ie',
    'zXoyGihFLI++Ad0Ivk5jvO8+r1O0Ld09LttPsm40rK+7dlPEdJoCeRf46ICD/YrL',
    '7UOZmhXdA6MACgkQjhjogWc7Suvv0Qf9Fl+dKh80b/AwQJXdtHjw6ePvUFhVTFcA',
    'u57Cx7gQTmsdFm2i9UWvb5CBKk04n91ygTK8StOxz3WAPFawJvuLBzobHXfrCrHH',
    '6Q6gjjAiagMouX/t6bGExydrPjHFiZrcdZDFqWyEf4nr5ixLISu8vUc17eH5EZhk',
    'EI60kmrH+xgvHa8wj5V2yk855tUr27BU2TOtcMgczT7nQhM4GWvzqyQxgvfvyXmY',
    '8Lb9xUxv5RtWxkDjbbDa5dsKjquy7OPg857N8AizSsAK4Q4q9c8W5ivjYCegqv3S',
    '+ysgG+xjsUOP8UzMbS35tIlmQ8j0hO7JuY1Gm0WnPN5PIJFZjebxjQ==',
    '=dVeR',
    '-----END PGP PUBLIC KEY BLOCK-----'].join('\n');

const pgp_desktop_priv =
  ['-----BEGIN PGP PRIVATE KEY BLOCK-----',
    'Version: Encryption Desktop 10.3.0 (Build 9307)',
    '',
    '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',
    '5g==',
    '=63Nq',
    '-----END PGP PRIVATE KEY BLOCK-----'].join('\n');

const rsa_ecc_pub =
  ['pub   rsa4096/C9DEDC77 2015-10-17 [expires: 2018-10-16]',
    'uid         Google Security Team <security@google.com>',
    'sub   nistp384/70C16E3C 2015-10-17 [expires: 2018-10-16]',
    'sub   rsa4096/50CB43FB 2015-10-17 [expires: 2018-10-16]',
    'sub   nistp384/102D9086 2015-10-17 [expires: 2018-10-16]',
    'sub   rsa4096/DFC40367 2015-10-17 [expires: 2018-10-16]',
    '',
    '-----BEGIN PGP PUBLIC KEY BLOCK-----',
    'Version: GnuPG v2',
    '',
    'mQINBFYiIB8BEACxs55+7GG6ONQV3UFYf36UDSVFbuvNB5V1NaEnkY0t+RVMigLR',
    'Zdl0HHsiaTKfKs4jqjLQAoR6Fcre9jlEhatotRg3AvHV1XYebxRlzdfXxyD0d6i9',
    'Quc1zbca0T8F1C5c7xfYP5g9iKWn5yFtHC3S7mLeOg7Ltx84bTo8AF7bHGA3uIQf',
    'uCtE8l6Z57HTeaf2IR/893jLOir8lvmTef83m/+e1j6ZwmKxxZO2s+aGKre6Fqsz',
    'Oo89CpWKNrdZ3IN8+Y4udZNlr7u0os7ffY0shfbLrqt+eVEu4EHfbpQTJxvalZJK',
    'tEnGtV8S7Z3dcPcimxvO7HZu7Wz8VnRzY/AZtee4fC+i2yBu1rWKgY3V1tFKdxVr',
    'KDnmS5MBgBAxv69mM3bf8QPinL4mtIQ65/Dt4ksJuysRmGwQ8LkjSLQCMMepnjBs',
    '/63wJ3e4wN1LCwnJonA2f8gZQHNeGPUhVVd/dWFDtmQaLwKFcI0GS/DiUPBIJir5',
    'DWnrEedtlcSLlwwcUglFsG4Sds/tLr+z5yE88ZrDrIlX9fb9cCAsDq7c8/NCzgvw',
    'kFez14sXgGhMz6ZfFzM49o0XwlvAeuSJRWBvnKonxM7/laqv4gK0zur3a6+D6qCN',
    'vt9iWO/YG+0Fvhmyxe34/Q71nXWc9t5aLcokmYLGY1Dpzf9oB8hDRdMCAQARAQAB',
    'tCpHb29nbGUgU2VjdXJpdHkgVGVhbSA8c2VjdXJpdHlAZ29vZ2xlLmNvbT6JAjwE',
    'EwEIACYFAlYiIB8CGwEFCQWjmoAFCwkIBwIGFQgJCgsCAxYCAQIeAQIXgAAKCRC4',
    '5BBcyd7cd8MzD/9YdMVZniQH4qBKxLFIoYGfLzCEI0S9IVUA37wrZ4YiRODSJRMf',
    'El6oVfTO/g8xpeQlDgHj1w2IDoSkeQrY+7rf9H41sGGOBDGXSQT+7Z7XFH2mPPvC',
    'cqYqR32BDNDkO/LL1BzzRlQvNmnGHxo098sqTgb7hoVsP+qFoem7JUMpcAV1KrUo',
    'P81haV8a/25ouWFZu5P68WFh861TyIjIYLQCns2fG+zlKFGN9Uynv6E5+Qk7dmni',
    'XnHRaiYZP9+wux6zm5a5wD/h6Iv4hyg/0Vnx5SyH8QOm3Qm6pkUciQkSmZQvf0r7',
    'HTLk19V1WtAp64YyUgnp9P/dq1bkclZcmWgZwVf88P8Cjm1BLh9RMdy6F+lVuUbz',
    '0JtOyxFtxfZ7ooNzYf8cZbq3IkJtFW22BcHm7jK7fpkwqVvTeK7TS1nvbUjMW4Qw',
    'bcFUJnA5TPkJanoNH9DCya7/PhbAI9hwyOcCsCOIfbIpj06izxxUXu0MJb+9k5US',
    'n7wRLwVsrt21V/PZoqvKMehqZTsVCsWZOzwf7UUY+WGZqT3uORopg9vadj1nSmLA',
    '+HprKhS9m3PA0vWbNvp0NQUWoanUjtpnCBuLk05H2GNgnRMnL0pEIkF2sTaCRjnY',
    'zLSo9QuzrvTgZ4McfcZ28MDuRR4JfS+LZ8AhopdjtR7VTG9IAxfq5JORpokCHAQQ',
    'AQgABgUCViIlJAAKCRDHiaFvb01lGfBgEACw5hlr7fWwSvYf1/Dfs1w5WyKc8cJs',
    '2370rVOzauVnRsFXTcl1D4iYnC2Uu2CwTcbD5pFKikpJnhDxzd6Ub5XapJrA06lu',
    'uGGExhCV3QKJVOrKJyZ+eWh5wu4UbDxSCvLQI/FLV6uLrbauAQpoFBBw2A8epRbY',
    'hqDdJ+EWgt57KfzsAc12jQ2HYGDIrdV35g3D4QANDLl69XLlSuyAHDMKRTs0rXje',
    'H6ds+/s9khKcCwkzOCAJSZHg83rRpLMkN0Izr3ZQB932Ybr7ZvdbkjHS6YhYfXzm',
    '1PIyFq9TikArz8YFcLQEgE6mph+jfEXMEzbg8G0+Wvrl0C0XHJWiCvl7feAxftGV',
    'w0HPWvNTemD7BCtTVEkIh5IOeB+rzdnFaW84PSYmwoPW6a4aOhQ5Y8QyshCA2fnP',
    'eyQACNpvj4nCJNdvyJAm2+5U/TnCEyl7zizm++sJTxAilqXxH5ubppaldmcRYLWZ',
    'pHN+Aup+yiotDRO4s9QunDC6vTGf4Zbe4xN+rL9vlaIH4dU700xFCNY5yCPqIst+',
    'pLwZo6FduJLsjE71z8UINxr4q0jXDaMyMm70xcDRDhvTPZTP/i3rFrM95x4Q/das',
    'ebNidE0mel0vHJ/5411OrRTCQ5fgv1i7ukZbVATWMOkYTpiYKv+sWPZg3uNxlqHo',
    'BmIunwzFda9LD7hvBFYiIcMTBSuBBAAiAwMEAeDSwQIRp955OGPU5A242FIJp91t',
    't1+YAVblSkJ+APKCdgEXeIcDheRcozUt5pOvGdibnaPotPCxdUc9QWYV8CFadyZg',
    'QOM57kCSnhTutzPccOLnSJVNy9sUbV91lMzBiQKlBBgBCAAPBQJWIiHDAhsCBQkF',
    'o5qAAIoJELjkEFzJ3tx3fyAEGRMJAAYFAlYiIcMACgkQaEJ4Y3DBbjzLUwF+IF0t',
    'U0CuCwddi9EYW3d66Q9dJv2H7V6oPNJ98mukzGUb7bBZhGdtFn1IGr3nSPgbAX4p',
    'AHfWy+JFh0zlM7HFJPECPtBi1UvuNFxvIZj/FeV/jdqaE2KLwO/9Gv3rPMQ2TurH',
    'WhAAo/ubNGuGZ+r/NI/Z/l9vLKfPVIiR3xtrehyV5GmMGXECoT9hME0jhg5RlSzK',
    'qxZkPgVmQclD3smbudp79rtK6T18DjlA84aXut+5ZhKiVPcyUK80UqNw7/3t/NsM',
    'xXv8z73O8glx3jXGv1zIYW8PHdeJOr7nX89dsM0ibgf7Ti3fdhygMA3nu/sbmrHL',
    'nQ3cix72qGQkMURjBRcSSJu2hMZjDNSPgOPOEABefxIyWG4kQwRRUXPePeJOVa6d',
    'QBJPh755bsbl3kQ0tG3NL9nDNq42M8QGDWnMpP9F8nmFSCw+RTUT5SminWsGhovW',
    'rG25/gkWrRZhMAAm0Bf3y+yMDWdsrnUCOQsgihQcH8i+V1AMfZgjJKPg1vtFdDCh',
    'uGtH3vJSEEhPZjTBBzIQx3etKoVDP8WtNZN5jeh84FYHsivLxSUiPQ//Jk3cnBLx',
    '/0f5Wrimwk7eUi4ueNUyFSWv+soi/FpcnDSvbVMVY2sIXI8aFFDv8U6+EPMyijAf',
    'tWRR4yA8tx0APRh/5z5T9sKj/n+jBZkQXBSKDnI7U4fmTBgh/sPeH61/zOuJBt6G',
    '9tfOmomf9TiTVQdD8T3HpEfJV5rrOFj8fic8OKSWp29jnoP57bIEprSgVTcrlK5b',
    'yr5qDMKEh2P7pgWfLWQsSG4a0iwJUsq5NGOsluzeH4aqDs25Ag0EViIh5QEQALcO',
    'QFtQojykqZmX/oKgAcRhiNM9NZbz3FGED69jesy3VOZxBeiCHO3vkHW9h6s88VuM',
    'qiC1JfZcH/Kkw+XAC+GtYxRMxZhDQ8pIh4PAFnaWRp5kAmmxS+k6O4tEQogOgh0k',
    '29P4+w63cgjw8mvb8acKOyMOCXLgnVNak614ogAFnrCakfA4WQOPGoqrey7z0XKJ',
    'LTbt28W2RALbSoC6KE7KTsx63Jng4Yr5q+elVOqzaSFPeloiC2R05CF6pCsVKX7D',
    'P0HFjcCk7/W8czeKOQWM62edgL4Y3c/x/g/PutAkLOrX/Wt1MejKeXT9QaNAA6QW',
    'qASkzK6L1FGrCzaf6cVZrhBdGdIatqYxpfY3I6tTtlN/5BGieFYXmZsP7t/p7TMv',
    'Jv2oJYtL1qsapQcnE9WOiARRb34hcnfA3UOet9W8vJqCGUYKZbJPyk5eLGuFVuDX',
    '6tnqUgoTkWRhsYNFqop2GnfZIl4a8doZ05oQQlKeRBw8pgnRCRq1fq28Yc4FqiXn',
    'Lfdts5016hc8U0KimMzvRBlSKTLEHC6febqq3XHDR7nHHrXxY29BVFD8r3izkT71',
    'Xb3Ql8NGvuWcnTS9j5L1EXkFv0wzFSUS5FUNU3JoNO5JsPl+YVczU6RX/QoDzpsx',
    'mJ7ctY0yeSEY2YXvuS6gQXDALx5D9zyCMTj8TrvTABEBAAGJBEQEGAEIAA8FAlYi',
    'IeUCGwIFCQWjmoACKQkQuOQQXMne3HfBXSAEGQEIAAYFAlYiIeUACgkQD8lB2VDL',
    'Q/tq9g/+N+kTlYxpQCvgvjJEM+VLVqUIv7wBqrZXawcrti8DBtVCcuvHYGjVmPqB',
    'OGyp6TNQTX5RQfo64TTh78BnG9Tf08oGv5nzXHxRdk92XZzzS2tq24j1OGiZhhYp',
    'JcFjzBx3qRhYmvN2ZkuCL48tthjKBx/SjfcGV185meNIZWzg67hmo7Szlbpo4lN6',
    'aLOxVAZelZjH3bFwpMp198ZEuE0B9RzhuJmhrtpl6dLtcQ8rsgy0EdwYons61GU2',
    'gnpn39kpCRSnmbMYqRfTyHo/pVLxz7XR98MrvB6am9wVE42PQV+viyHLB2pRquGZ',
    'CSCfMrzE38MMJ3BJAcwx6YcAItaBQXaWYEyE/ixr4OvEA+jC4n0Nq8Pik/oUc+7I',
    '2LWAZ50VrE+HroNVomFMMUvp+RZ0S/+J4DuuiwAxnN4oacYQVKqDt7D0V+8da+ee',
    '87ghOrL5xTjG1yEgd3Q9VDbh8gWGtVWevdnAldZzDvYsVsJW4N8YunVOLZZ0+24R',
    'X9LUsJ6Fry7oP4kvOFGFegVC123x7HDrR9333Eq4H59xHXyDQo0O7NvCph8RfSdj',
    '/ouYP/D1/gkS45ladT89qePrwXT6j8DTqkMmrUbXVXtc9tBWXgNB0nacX68TywP9',
    'LigrBsDiPdwYszKKuZWCEhex5BQo4Pfw8OBHqkENQdMmUgW1zcE4aQ/+Ioq5lvlH',
    'OpZmPGC3xegT0kVC0kVeK12x3dTCc6ydkWanXrCJrCXNnboV34naszTl+Qt75TyB',
    'XqFJamwxjA5K/COmAZTAcW4svGRhqhAMg02tfkrL5a84lImOVmpGbvUAQWBXNKXV',
    'aeOmKVEvO6e/JBVKDQL5h+ePJ1csq8I5P5zelgXWgVkFvlq0H1MrF3eU780A1hLB',
    'Q4O8eJ+zoCLYaR6lBvZTsfVtsdIuIodiJudYB9GUDMcalB7wj/CUN06R/UcDK4HG',
    'qGb/ynS/cK5giZE6v2BNA7PYUNcdr6hO51l3g7CwswZTnx79xyPhWsnOw9MUymyv',
    '/Nm73QX/k635cooVPAaJOPSiEsboqDCuiAfuEamdrT00fUfqCkepI3m0JAJFtoqm',
    'o9agQBSywkZ0Tjuf9NfB7jBWxIyt1gc9vmiCSlnbdDyK/Ze17PhDdkj2kT8p47bN',
    'l2IBk48xkrDq7HfMNOXC50jyiELs+8+NIfwICBJRyMpCQWAs9d+XBnzRzLXmEA/1',
    'ScdNX0guOOSrTsfIgctO0EWnAYo8PfF9XebZMhTsOhHmq4AAqWFBYxAQa6lGBBcU',
    'fZ0dHylTnuiR5phXMyWYWplZsHOVaHnhoGz1KJkpqYEH7fp38ERdcRiz7nwoyfYz',
    'Jl5qaAebTt8kYtJm3Jn8aJCAjPwtArRzkHO4cwRWIiISEgUrgQQAIgMDBNbEs2RY',
    'eWTLtXrcTUYDhMVzZwsTVJPvgQqtS+UnmPA7+qLEjSInHFfUE0yQEYsCTzP3g9mr',
    'UOte0x/i+u7bmvxYo58SZ51bEd4/IbKecgSJbwLkhHR2HeHh3MsuW8lVtAMBCQmJ',
    'AiUEGAEIAA8FAlYiIhICGwwFCQWjmoAACgkQuOQQXMne3HfJkA/9FIOskOWRjm4e',
    'UuocsD1Rwglk3nWUAJ5krHcKI6/LrKP0OdOnrXrd65FYwpYvhf6/6OCg+NXvQ7T/',
    'rFs+Cfi+Llko5gDWVEcyPOreN/E9R7rVPxYeqWryELFFXL4eWGA6mXRW3Ab3L6pb',
    '6MwRUWsSfXjaW1uyRPqbJm0ygpVYpVNF9VmI5DvMEHjfNSxHkD3xDWZuUHJ+zswK',
    'uAeRtEgYkzARZtYGBiMuCjULD29cYHaaySxY94Be/WvZI6HnCoXSgQ8LCpTGkiSL',
    '9cLtYIDxq8DmzJhiQkQItxzJRPUTMDZUR+SSNAqxL0K5ohuNzZW8hDfkdudZ4Pr6',
    'u+sMVHCIG5sL6IHF35dsoUceCML/rTrM/3JYPADuleTmKfv2Dt78FL4s2CNxcBfI',
    'SHjYCquIb5xyc8m222ya8eF2CoSoC1XhChoGjcIbKvHxcK/PgGgrFLI1NaJRN8vR',
    'qCiW1bPNg8cAyLAb5pdtutlsxrhvRlRc65qNBEJ711Gymd54DOK6vW6DRFQPZLxW',
    'MoElc/Mio4X3FA+40kKXXUcBA3Y2qi1vhCottZIXd+37HZZc0WwoLxv+qvwB19IE',
    'SRuRhJyHnuYXHX7Y+GwDz7/7bzxRrEEhcQfzcWp4qhoFc8uCScj98kMeEiW3AQmU',
    'ayyFDmvqEREd2cSpUbrIJVLT2aEOfKe5Ag0EViIiPwEQAMminwtRlkfMZCotqAo2',
    'GOmJb6gSbJ9GPFaWDBZVMXR8tHmbFlXwsVmuSkV0BS7hnE3N0dbvv5hAv9uNjnqA',
    'vxjP1aSfPNWVOVYSLl6ywUBDasGiiyxf503ggI7nIv4tBpmmh0MITwjyvdHSl0nt',
    'fC7GrdFxTX9Ww655oep3152a33eaos1i3CZqB9+zuyqfe4NWbyaYBoCfESXtmEY4',
    'AbMFy/xYB6liRJsxCeOo4u+is4jrICwGyMZCOsgswciMIh3x3/K1aa/v4DS/T96V',
    '8BTqYeSS9nIGTkz2jLIRXK43wX07DpsoeQvUvWjmfaqUvQluixvwdE/IJ6O92PiC',
    '+0U1CYP5KM0+fpdh2BhaxHJrs2b4NEsYHuheeZ485HrCX8ZamUMzj2+bC0q/OYHP',
    'UtABk96gjXPmTfme16knDFlRJFPZytQ36p9lGYTCUIMwyxjMfi9E+HnhoJfsqlbk',
    'kDseDEB2nU9SJb8NRPmMURVo+yayqcyFUJ4ZimJJ1MpGvlHj6mdxzIdJjzoT541H',
    'WKz+SvVSjCRVFNCjvmQk31/BiPmCf62+KYOpv1tkOankrYc1yX6kt92+JmG6vIQT',
    'u1Lqbp46jkydyG4BAkv9l8EfUMyPaLglTTMotc62rwtPEWnPoFAcV6ZjTxwMx029',
    'hzFIp5tjvoxz7AkuGbi3yoXhABEBAAGJAiUEGAEIAA8FAlYiIj8CGwwFCQWjmoAA',
    'CgkQuOQQXMne3HdgVQ/9GjK+aYHgcuGFw1bX8EfSZjmEvdnuePT0Fv9Padqs236P',
    'COmQcU/1EtXhrgO8NzuPb83IasJWyvo4xagCnCiAJ+uk4P4rK6Sbb3VZ+Hm1SyOF',
    'SF3P7JuaSC03k0aD03s2JxSbZoqupoKkEfLlat0J9HoqquNdjUZ2+4aETcZcsXt1',
    'WVGkzbgwqJbLiuaRKLOvJjMICQA5zhljy7WcIOzIkWyhxhpzZ+a9kdXXWJLI0nkB',
    'jT/5UYT3DNODssrNEfayzxZbvf3Dtl/OIrmKQpgWtVOaiLcxI9FzUN6pGxAlBdP2',
    'rmj0MPQIpa17T76d5P/VZrR/SYeEsPaPjGBZFOAW1yTef0mXKQ0mc0nwTGHNYjrs',
    'tkBUh/F9ErKN/++UN7pDc5ORVCbg5Z1gd3UIL16lsYnNyq1O0cdWgW+xCUMLVKb5',
    'Q9f59ld3/yNF5XPyPNH9Ybb5kQJjYsDaIa+NPg9YLZ8DdONgqZyWgKiW5klMSk5Q',
    '1+pxcXjT13eX5L0Ru/w3UjsSaCQOA/OuNep7Nwg29tWogTOSkhwC92Zpjd5PfoJi',
    'j3EuhPUeTupRYM58jib/b9/1mQ1+wVyDEpIxTDjU0x1u4E59HcAu0naLNGd9bJMw',
    'EeiVzNNyKUihENSQh9nsPniQvXgF3pPGQ8ZpS+9R9NyYQID5t3W8UrLpguvAE2U=',
    '=Q/kB',
    '-----END PGP PUBLIC KEY BLOCK-----'].join('\n');

const valid_binding_sig_among_many_expired_sigs_pub = [
  '-----BEGIN PGP PUBLIC KEY BLOCK-----',
  '',
  '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',
  '4z6aN5G1sT5159GF',
  '=yzZh',
  '-----END PGP PUBLIC KEY BLOCK-----'
].join('\n');

const key_without_subkey = [
  '-----BEGIN PGP PRIVATE KEY BLOCK-----',
  'Version: OpenPGP.js v2.6.2',
  'Comment: https://openpgpjs.org',
  '',
  'xcLYBFp9nCsBCACXTmLI9bJzaAanrD7r6j7gNDS7PsebJr0e182hgHVnGkr3',
  '8XCsCdWSllUNfBRln4MI8GfWVO5Bhhx5en6ntCptJVeSsohAHfBzmdoauSGW',
  'y+M+3dlSGeVqgqmDukQSxuNgKBC/ELDhKvAb8uKWnS/MUOapk/6aF8mf9Vqm',
  'eG/1RHrIvxfeOsRCEFH0OqB2tOeCWPXohxpzv2AvFxWviwzpedwNGDhN/XjZ',
  'JzI4LyBKlorHJvwe4KLKtaLuOq0jmNkT6AcsniyhvqN8QRP4OK7084Uc/7Yd',
  '6Qrcnw/6plqMB5J2PyYkB6eTptp28bwIxUGzfGQ6qfDyHHQBIbAVt3m5ABEB',
  'AAEAB/9uDdjynSvon5C/oxy9Ukvbnn2AeOCNLLdA2O07/Ijoroo7IIW4zQpo',
  'rio9PbREWqrf9KVCk9IdHORXQ88eQoDdlNzG2k8ae+xq2Ux4RZJ18eVf09P/',
  '0NA7EcElDHX5RmsahOnxX72YejfdzGQd80VSEsJENF5rTMQeMkN2dIHS3pFM',
  '9ar2nJe9dc/L9ND0P79X8twZvvfh287Tm23fs384nRedcUwELm43kNV7Us3t',
  'ub1ORmAzHhVCa8dWev7Zca7FqiZxa0u3X/QHvVMMpr0ewTBulr/mEjaglfYf',
  'dNp1PxduWYPWU54/XLG3G4nqLUS++qjd3O46VhMMCIigGf01BACgrkPwdrTJ',
  'EGCfgIq48IGoMU//wS1P0g7EIzplwGAzGAJQw6LhGqKrDONcyKGqHzRgn8oz',
  'dF8iezGjlVq7oiyrrB4ez1gDG4RRDC+6+PTn/TXBTZ21krUgPUrB0jcqV7SQ',
  'IIWZost7zNcbEqiPI91SPAMwYJZbJrSL4pTnDVLfewQA8RB1y3IzuK/rT+gs',
  'JfcSHqZ12G+sUIgpK6yv4pN7hQDhWC3+qe8ULnLLXYv+FQslnRW7tTkAbCRl',
  'kJvbibRqrYj+fQS2d3Hau5HYcGKcv9KPgOhB49yRkQpWCT+fqsQwJByyeZ47',
  'iiJRR8t0X92nr0zbf0f+LalmK4cQnQ6LS1sEAN2R8RiamrNcbsdmre0v6QVL',
  'WUOIwRWABRWFOm9QbSr80ji1q9pHlS5WbIw4LVeiO8V6H21QTL2fqDA9yWOK',
  'mNsOgIi+1PMkC4lwPu60VR7yBtLFWFF2SuuqPuDG8TFA2PBQFisrxcq63E38',
  'kroxpqxNCXXuB3E0uNL2fO6dqWbaRPzNF2dpYm9saW5AcHJvdG9ubWFpbC5i',
  'bHVlwsBcBBABAgAGBQJafZwrAAoJEFu1JX+Hv3FrMWEH/jE6HN5MayB6RHe7',
  'FTrfMlMEh54BqsiugmAIgtKYcxUcNsPw/hC53lJ6tDzo3/zk/2shvfItafh5',
  'ldUsERj1y5e7OMR+2GgfgMdddLddBuV8sXv2HwQgMtykeXOIPuH+7CZDwV7F',
  'lUyrykwpIjGGPkK+fG64fVt0cfWprdEsqcGZmHf/lHtoGprG8syfF+Ao3beI',
  'g6HJ61NHIBy4ewueKMBZ58/9VF2MQ7YgBQCtQNAnQKKrDFmxjZw3J4zBl83i',
  '3LrYpnYepvMUitQ/Y2pBAYygUExZ0dPC2uGFdPISbDGLg3DhGcyy1MvbLuNh',
  'EyjB8RncAfSIwK4dSGVh+PD5dkc=',
  '=w6Dj',
  '-----END PGP PRIVATE KEY BLOCK-----'
].join('\n');

const multi_uid_key =
  ['-----BEGIN PGP PUBLIC KEY BLOCK-----',
    'Version: GnuPG v1',
    '',
    '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',
    'ljIYQms3pCv1ja6bLlNKpPII',
    '=qxBI',
    '-----END PGP PUBLIC KEY BLOCK-----'].join('\n');

const wrong_key =
  ['-----BEGIN PGP PUBLIC KEY BLOCK-----',
    'Version: OpenPGP.js v0.9.0',
    '',
    'xk0EUlhMvAEB/2MZtCUOAYvyLFjDp3OBMGn3Ev8FwjzyPbIF0JUw+L7y2XR5',
    'RVGvbK88unV3cU/1tOYdNsXI6pSp/Ztjyv7vbBUAEQEAAc0pV2hpdGVvdXQg',
    'VXNlciA8d2hpdGVvdXQudGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhM',
    'vQkQ9vYOm0LN/0wAAAW4Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXq',
    'IiN602mWrkd8jcEzLsW5IUNzVPLhrFIuKyBDTpLnC07Loce1',
    '=6XMW',
    '-----END PGP PUBLIC KEY BLOCK-----'].join('\n');

const expiredKey =
  `-----BEGIN PGP PRIVATE KEY BLOCK-----

xcA4BAAAAAEBAgCgONc0J8rfO6cJw5YTP38x1ze2tAYIO7EcmRCNYwMkXngb
0Qdzg34Q5RW0rNiR56VB6KElPUhePRPVklLFiIvHABEBAAEAAf9qabYMzsz/
/LeRVZSsTgTljmJTdzd2ambUbpi+vt8MXJsbaWh71vjoLMWSXajaKSPDjVU5
waFNt9kLqwGGGLqpAQD5ZdMH2XzTq6GU9Ka69iZs6Pbnzwdz59Vc3i8hXlUj
zQEApHargCTsrtvSrm+hK/pN51/BHAy9lxCAw9f2etx+AeMA/RGrijkFZtYt
jeWdv/usXL3mgHvEcJv63N5zcEvDX5X4W1bND3Rlc3QxIDxhQGIuY29tPsJ7
BBABCAAvBQIAAAABBQMAAAU5BgsJBwgDAgkQzcF99nGrkAkEFQgKAgMWAgEC
GQECGwMCHgEAABAlAfwPehmLZs+gOhOTTaSslqQ50bl/REjmv42Nyr1ZBlQS
DECl1Qu4QyeXin29uEXWiekMpNlZVsEuc8icCw6ABhIZ
=/7PI
-----END PGP PRIVATE KEY BLOCK-----`;

const multipleBindingSignatures =
  `-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2

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
p92yZgB3r2+f6/GIe2+7
=jZgG
-----END PGP PUBLIC KEY BLOCK-----`;

const mergeKey1 = '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' +
'\n' +
'mQENBFtDaAIBCACX5Y/YO7CuP6PMBIJWUMXFb50cGgzzowCbhdzpYU589iz1npjR\n' +
'yBmZPmnKK4KfEMz0buY+763/LFwihbfBh5jsh3oV14rqg+P6VNLeCATuGWO/5JKy\n' +
'jRNzjmQZFLcmbStF1W3+vIvJJDibMqvjHLE33z7t17BLU/fVu4F2BuuKVsM5xm/J\n' +
'HIYFzCeWR5O8+0s6Kd1SKZwzy7ySBV0w3Pk0go076RnyKyv8vneogTubA0qSAKJx\n' +
'jm6k94wJSSt3CyH5ogcLd4wjsylA65wOPIy7ROvcg05hdWO83qto4tE8o2mpB+Wc\n' +
'MZ6gkyLZnQEvKBKlh1H2BBrnI2w4iDRVSCOVABEBAAG0JVN1YktleU1lcmdlIFRl\n' +
'c3QgPG5vc3VjaEBleGFtcGxlLm9yZz6JAVQEEwEIAD4WIQSJdpCFeXsnZzf+xlKb\n' +
'N/Be0N878AUCW0NoAgIbAwUJA8JnAAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAK\n' +
'CRCbN/Be0N878MfWB/4wEIXGoYc8sYcFIjeRsIniQN+TaOhKY4kOdbk/MJh5hDcc\n' +
'OwXpahc6C14pzSh7C5bkwRzWrm0hsONR5uhrx09154GU5ie88yIKTYC58ef4TwB+\n' +
'Kq4UvOV0xbkFGmyGhlDWgA9nSCotHzt//9fLqY26m7pZ1JVczDWVHIqwTv4lAF5G\n' +
'fBuDEV9w6fcbvIiqSrTx/lekNQjCE4+JhBahindko4jeP4bj/699Q0f+j2pHJ5xU\n' +
'zHoWAI8RowX7EDzwydnTG0Rrx9QoN2QcUjw6Lsg9//i7fk5PochYa7kGYcHGLvXP\n' +
'8fwk7K1be8ZnRwUx8dqzoQVtYRxdHP19P796PD5guQENBFtDaAIBCAC3FKAMPRU/\n' +
't03vbsVibHkpCI6KVaInTu7+HWksYQ8gp89w2nzQZLvAfIMKJBVdZa+nRoTTjZ6B\n' +
'zwmvtiCjv202/9L8BcBmsNFnKapgi8bD4L8r/9lSMngD1ebSdVuopNQXzDXLYsKl\n' +
'8OLup1AFPQPEwDnn72pHF7fIJBOJkuXnS9syCViLlFeziBGsY/RD0hWE7YgIK+m0\n' +
'0M+57EzDntjsVTI5d3V8EwEUJU1nADtnbkjQoyCXBfqxYe4+SmiWkyFKFVfIQeX/\n' +
'muoq79b9/NVM7G+vTcSzTCPKKKdw1Zefb1i/S/O1HWwA3KJCFYOMPtqLLf2hIF/5\n' +
'3LC1SRVCJ7bHABEBAAGJATwEGAEIACYWIQSJdpCFeXsnZzf+xlKbN/Be0N878AUC\n' +
'W0NoAgIbDAUJA8JnAAAKCRCbN/Be0N878Hf6B/4nun5NklDp/X5EvhHKdTgOMlIC\n' +
'f0RsrqRGvQTOMmoxeQ8w88GkTuGIUSHWPxXPracNfqxETOY+D91dQDKpgIMSPqDk\n' +
'tAEnXhX2S36Eb/68hkkwOF2I5Ngcv39n6BLvREGf8JiUR7O/MRgfcjebfH4Trc/K\n' +
'XorBDo4y3g2wg68ueuEQHfi8HprWec2QjiSgTTaNfG0oS+UKLJB9ZsPhVB59lE4B\n' +
'giI/4DD0FYR9pUfo9SG2sQKWlD5jIWob5S8x2QYZKFXYDEGX7V9/yjReGAfqjhQY\n' +
'EPmHvKuRRWbzEP0ckFPVsyc6E07OzZyfnHOPIGXH/IFO0OF7Zj8Cvh8BaPYW\n' +
'=hJLN\n' +
'-----END PGP PUBLIC KEY BLOCK-----\n';
const mergeKey2 = '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' +
'\n' +
'mQENBFtDaAIBCACX5Y/YO7CuP6PMBIJWUMXFb50cGgzzowCbhdzpYU589iz1npjR\n' +
'yBmZPmnKK4KfEMz0buY+763/LFwihbfBh5jsh3oV14rqg+P6VNLeCATuGWO/5JKy\n' +
'jRNzjmQZFLcmbStF1W3+vIvJJDibMqvjHLE33z7t17BLU/fVu4F2BuuKVsM5xm/J\n' +
'HIYFzCeWR5O8+0s6Kd1SKZwzy7ySBV0w3Pk0go076RnyKyv8vneogTubA0qSAKJx\n' +
'jm6k94wJSSt3CyH5ogcLd4wjsylA65wOPIy7ROvcg05hdWO83qto4tE8o2mpB+Wc\n' +
'MZ6gkyLZnQEvKBKlh1H2BBrnI2w4iDRVSCOVABEBAAG0JVN1YktleU1lcmdlIFRl\n' +
'c3QgPG5vc3VjaEBleGFtcGxlLm9yZz6JAVQEEwEIAD4WIQSJdpCFeXsnZzf+xlKb\n' +
'N/Be0N878AUCW0NoAgIbAwUJA8JnAAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAK\n' +
'CRCbN/Be0N878MfWB/4wEIXGoYc8sYcFIjeRsIniQN+TaOhKY4kOdbk/MJh5hDcc\n' +
'OwXpahc6C14pzSh7C5bkwRzWrm0hsONR5uhrx09154GU5ie88yIKTYC58ef4TwB+\n' +
'Kq4UvOV0xbkFGmyGhlDWgA9nSCotHzt//9fLqY26m7pZ1JVczDWVHIqwTv4lAF5G\n' +
'fBuDEV9w6fcbvIiqSrTx/lekNQjCE4+JhBahindko4jeP4bj/699Q0f+j2pHJ5xU\n' +
'zHoWAI8RowX7EDzwydnTG0Rrx9QoN2QcUjw6Lsg9//i7fk5PochYa7kGYcHGLvXP\n' +
'8fwk7K1be8ZnRwUx8dqzoQVtYRxdHP19P796PD5g0dFT0VEBEAABAQAAAAAAAAAA\n' +
'AAAAAP/Y/+AAEEpGSUYAAQEBASwBLAAA/+EN2kV4aWYAAElJKgAIAAAABQAaAQUA\n' +
'AQAAAEoAAAAbAQUAAQAAAFIAAAAoAQMAAQAAAAIAAAAxAQIADAAAAFoAAAAyAQIA\n' +
'FAAAAGYAAAB6AAAALAEAAAEAAAAsAQAAAQAAAEdJTVAgMi4xMC40ADIwMTg6MDc6\n' +
'MDkgMTU6NTY6NDAACAAAAQQAAQAAAAABAAABAQQAAQAAAAABAAACAQMAAwAAAOAA\n' +
'AAADAQMAAQAAAAYAAAAGAQMAAQAAAAYAAAAVAQMAAQAAAAMAAAABAgQAAQAAAOYA\n' +
'AAACAgQAAQAAAOsMAAAAAAAACAAIAAgA/9j/4AAQSkZJRgABAQAAAQABAAD/2wBD\n' +
'AAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcp\n' +
'LDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIy\n' +
'MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAEAAQAD\n' +
'ASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAA\n' +
'AgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAk\n' +
'M2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlq\n' +
'c3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXG\n' +
'x8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEB\n' +
'AQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx\n' +
'BhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5\n' +
'OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaX\n' +
'mJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq\n' +
'8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3+iiigAooooAKKKKACiiigAooooAKKKKA\n' +
'CiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKA\n' +
'CiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKA\n' +
'CiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKA\n' +
'CiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKK+QPib8Tf8AhY39l/8A\n' +
'Eo/s/wCweb/y8+bv37P9hcY2e/WgDv8A/hpr/qUf/Kl/9qo/4aa/6lH/AMqX/wBq\n' +
'rwCigD6/+GXxN/4WN/an/Eo/s/7B5X/Lz5u/fv8A9hcY2e/WvQK+AK+v/hl8Tf8A\n' +
'hY39qf8AEo/s/wCweV/y8+bv37/9hcY2e/WgD0CiiigAooooAKKKKACiiigAoooo\n' +
'AKKKKACiivkD4m/E3/hY39l/8Sj+z/sHm/8ALz5u/fs/2FxjZ79aAO//AOGmv+pR\n' +
'/wDKl/8AaqP+Gmv+pR/8qX/2qvAKKAPr/wCGXxN/4WN/an/Eo/s/7B5X/Lz5u/fv\n' +
'/wBhcY2e/WvQK+AK+v8A4ZfE3/hY39qf8Sj+z/sHlf8ALz5u/fv/ANhcY2e/WgD0\n' +
'CiiigAooooAKKKKACiiigAr4Ar7/AK+AKACiiigAr3/9mX/maf8At0/9rV4BXv8A\n' +
'+zL/AMzT/wBun/tagD6AooooAKKKKACiiigAooooAKKKKACiiigAr4Ar7/r4AoAK\n' +
'KKKACvf/ANmX/maf+3T/ANrV4BXv/wCzL/zNP/bp/wC1qAPoCiiigAooooAKKKKA\n' +
'CiiigArz/wCJvwy/4WN/Zf8AxN/7P+web/y7ebv37P8AbXGNnv1r0CigD4Aor7/o\n' +
'oA+QPhl8Mv8AhY39qf8AE3/s/wCweV/y7ebv37/9tcY2e/Wvr+iigAooooAKKKKA\n' +
'CiiigAooooAKKKKACiiigArz/wCJvwy/4WN/Zf8AxN/7P+web/y7ebv37P8AbXGN\n' +
'nv1r0CigD4Aor7/ooA+QPhl8Mv8AhY39qf8AE3/s/wCweV/y7ebv37/9tcY2e/Wv\n' +
'r+iigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKA\n' +
'CiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKA\n' +
'CiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKA\n' +
'CivP/ib8Tf8AhXP9l/8AEo/tD7f5v/Lz5WzZs/2Gznf7dK8//wCGmv8AqUf/ACpf\n' +
'/aqAPoCivn//AIaa/wCpR/8AKl/9qr6AoAKKKKACiiigAooooAKKKKACiiigAooo\n' +
'oAKKKKACiiigAooooAKKK8/+JvxN/wCFc/2X/wASj+0Pt/m/8vPlbNmz/YbOd/t0\n' +
'oA9Aor4AooA+/wCivkD4ZfE3/hXP9qf8Sj+0Pt/lf8vPlbNm/wD2Gznf7dK+v6AC\n' +
'iiigArz/AOJvxN/4Vz/Zf/Eo/tD7f5v/AC8+Vs2bP9hs53+3SvQK+f8A9pr/AJlb\n' +
'/t7/APaNAHgFFFFABXoHwy+Jv/Cuf7U/4lH9ofb/ACv+Xnytmzf/ALDZzv8AbpXn\n' +
'9FAH3/RXz/8Asy/8zT/26f8AtavoCgAooooAKKKKACiiigAooooAKKKKACiiigAo\n' +
'oooAKKKKACvgCvQPib8Tf+Fjf2X/AMSj+z/sHm/8vPm79+z/AGFxjZ79a8/oAKKK\n' +
'KACvf/2Zf+Zp/wC3T/2tXgFe/wD7Mv8AzNP/AG6f+1qAPoCiiigAr5//AGmv+ZW/\n' +
'7e//AGjX0BXn/wATfhl/wsb+y/8Aib/2f9g83/l283fv2f7a4xs9+tAHyBRRRQAU\n' +
'UUUAFfX/AMMvib/wsb+1P+JR/Z/2Dyv+Xnzd+/f/ALC4xs9+tfIFFAH3/RXyB8Mv\n' +
'ib/wrn+1P+JR/aH2/wAr/l58rZs3/wCw2c7/AG6V9f0AFFFFABRRRQAUUUUAFFFF\n' +
'ABRRRQAUUUUAFfIHxN+Jv/Cxv7L/AOJR/Z/2Dzf+Xnzd+/Z/sLjGz360fE34m/8A\n' +
'Cxv7L/4lH9n/AGDzf+Xnzd+/Z/sLjGz3615/QAUUUUAFFFFABXv/AOzL/wAzT/26\n' +
'f+1q8Ar6/wDhl8Mv+Fc/2p/xN/7Q+3+V/wAu3lbNm/8A22znf7dKAPQKKKKACiii\n' +
'gD5//aa/5lb/ALe//aNeAV9/18gfE34Zf8K5/sv/AIm/9ofb/N/5dvK2bNn+22c7\n' +
'/bpQB5/RRRQAUUUUAFFFFAHv/wDw01/1KP8A5Uv/ALVXoHwy+Jv/AAsb+1P+JR/Z\n' +
'/wBg8r/l583fv3/7C4xs9+tfIFFAH3/RXwBRQB9/0V8gfDL4m/8ACuf7U/4lH9of\n' +
'b/K/5efK2bN/+w2c7/bpXf8A/DTX/Uo/+VL/AO1UAfQFFfP/APw01/1KP/lS/wDt\n' +
'VeAUAff9FfAFFAHv/wDw01/1KP8A5Uv/ALVXgFFFABRRRQAUUUUAFFegfDL4Zf8A\n' +
'Cxv7U/4m/wDZ/wBg8r/l283fv3/7a4xs9+te/wDwy+GX/Cuf7U/4m/8AaH2/yv8A\n' +
'l28rZs3/AO22c7/bpQAfDL4Zf8K5/tT/AIm/9ofb/K/5dvK2bN/+22c7/bpXoFFF\n' +
'ABRRRQAUUUUAFFFFAHn/AMTfhl/wsb+y/wDib/2f9g83/l283fv2f7a4xs9+tfIF\n' +
'ff8AXn/xN+GX/Cxv7L/4m/8AZ/2Dzf8Al283fv2f7a4xs9+tAHyBRXoHxN+GX/Cu\n' +
'f7L/AOJv/aH2/wA3/l28rZs2f7bZzv8AbpXn9ABRRRQAUUUUAFFFFABRRRQAUUUU\n' +
'AFFFFABRRRQAUUUUAFFFfX/wy+GX/Cuf7U/4m/8AaH2/yv8Al28rZs3/AO22c7/b\n' +
'pQB6BRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABXz/AP8ADMv/AFN3/lN/+219AUUA\n' +
'fAFFff8AXn/xN+GX/Cxv7L/4m/8AZ/2Dzf8Al283fv2f7a4xs9+tAHyBRXv/APwz\n' +
'L/1N3/lN/wDttH/DMv8A1N3/AJTf/ttAHgFFegfE34Zf8K5/sv8A4m/9ofb/ADf+\n' +
'XbytmzZ/ttnO/wBulef0AFFFFABRRRQAUUV6B8Mvhl/wsb+1P+Jv/Z/2Dyv+Xbzd\n' +
'+/f/ALa4xs9+tAHn9Fe//wDDMv8A1N3/AJTf/ttH/DMv/U3f+U3/AO20AeAV6B8M\n' +
'vhl/wsb+1P8Aib/2f9g8r/l283fv3/7a4xs9+te//DL4Zf8ACuf7U/4m/wDaH2/y\n' +
'v+Xbytmzf/ttnO/26V6BQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFA\n' +
'BRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFA\n' +
'BRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFA\n' +
'BRRRQAUUUUAFFFFABRRRQB//2QD/2wBDABsSFBcUERsXFhceHBsgKEIrKCUlKFE6\n' +
'PTBCYFVlZF9VXVtqeJmBanGQc1tdhbWGkJ6jq62rZ4C8ybqmx5moq6T/2wBDARwe\n' +
'HigjKE4rK06kbl1upKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSk\n' +
'pKSkpKSkpKSkpKSkpKT/wgARCABAAEADAREAAhEBAxEB/8QAGQABAQEBAQEAAAAA\n' +
'AAAAAAAAAAQFAwEC/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB\n' +
'0wAAACY6nQHyTFYMsrKQcTONcAAAAiPSwAGSWk5mGkVHhARm4UEJmnEHc1ygAAAA\n' +
'/8QAHhAAAwACAgMBAAAAAAAAAAAAAQIDAAQQEhETMCD/2gAIAQEAAQUC+NLpMo4d\n' +
'eCQoTYR24vF2pBDOfFV7zlrv7PjexmYW9n5tsN3g5pPan5wEqZ7QwWmcN5jLbHcK\n' +
'pYxn60yuuHwyoOVjRjKQkPj/AP/EABQRAQAAAAAAAAAAAAAAAAAAAGD/2gAIAQMB\n' +
'AT8BAf/EABQRAQAAAAAAAAAAAAAAAAAAAGD/2gAIAQIBAT8BAf/EACMQAAIBAwQB\n' +
'BQAAAAAAAAAAAAERAAIQIRIwMTKBIEFRYXH/2gAIAQEABj8C2UefqMXZ4iyP2+qn\n' +
'LiPNzTASEBtAAZiPb0qg4jPM1j2jHMVY8ztO0004EQDis6cGdDdaT5nydr//xAAi\n' +
'EAEBAAEDBAIDAAAAAAAAAAABEQAhMUEQMGGBUXEgkbH/2gAIAQEAAT8h7OoZ+HDA\n' +
'z6fzq5eDnABo7dTgI9JnOE366qUxcDVS73tGmUXXNWEGumyfjoiBzvc4wmfeMSyi\n' +
'J4wy8HOQCr8MfgfemJRPouLBU3eXKZLxm5arXowtX9OOx9BcRGJEwFYFXIAXkTGI\n' +
'NN3tf//aAAwDAQACAAMAAAAQAAAAAgAAEAEAAAAAEAAggAgkAkgAAAAA/8QAFBEB\n' +
'AAAAAAAAAAAAAAAAAAAAYP/aAAgBAwEBPxAB/8QAFBEBAAAAAAAAAAAAAAAAAAAA\n' +
'YP/aAAgBAgEBPxAB/8QAJBABAAEDAwQCAwAAAAAAAAAAAREAITFBUWEQMIGRIPBx\n' +
'scH/2gAIAQEAAT8Q7JCzpQHylqYMsjlbPPUgJZVWvEAALtZz1NOQkkSANW+KnASm\n' +
'G4COcdTDBIXEiP8AKDEA1EoZiz2pSwLiFzRzaiI5ZAeQbZ+6fACsziEuuTFRgJTT\n' +
'YDPGat0gRi5nxP2KYC2QVCgMCMjymniaUDoTan2xT9pNwewik+Sw2NuD90JedBjl\n' +
'2OaiVfmYmDHFuhhnCj5nh+6zQxVScX2TSJyIRIRoE5EAEq0J3CgB+WnEplyJjBGm\n' +
'e1//2YkBVAQTAQgAPhYhBIl2kIV5eydnN/7GUps38F7Q3zvwBQJbQ2nuAhsDBQkD\n' +
'wmcABQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEJs38F7Q3zvwjvsH/jrxLY5X\n' +
'7qTHTBzsAt8yGRpFB0RBo4CI184t6KA7NpSmjeBiy2J5kz0RjdvEdj4bs5JKQkDk\n' +
'ikUr+3r79w/W04+KDrue1fXCKK9KfWmi/b3qcNBPkpgAhyROtCHHC7OaX6LHnm8w\n' +
'IPO4oMoyqW4wbwPdOyBLde3FkzOx8XPmvgzzBwyC3Wve3CC/PvEnmiT0EjYqAU1j\n' +
'piz7cVLsawElBi7rtA6Ryiz1/xY/LYPprGsLhvG3/wtD+dWVPPSd7xS2sl6C5KJB\n' +
'ZhKI1uIwdTCGO/Th6FKqO/9djRzOgRaPwxe5uR+HTcgWRAUXlzU9AKzWikIBo8Iu\n' +
'eQc3Ss7SlRnwn365AQ0EW0NoAgEIALcUoAw9FT+3Te9uxWJseSkIjopVoidO7v4d\n' +
'aSxhDyCnz3DafNBku8B8gwokFV1lr6dGhNONnoHPCa+2IKO/bTb/0vwFwGaw0Wcp\n' +
'qmCLxsPgvyv/2VIyeAPV5tJ1W6ik1BfMNctiwqXw4u6nUAU9A8TAOefvakcXt8gk\n' +
'E4mS5edL2zIJWIuUV7OIEaxj9EPSFYTtiAgr6bTQz7nsTMOe2OxVMjl3dXwTARQl\n' +
'TWcAO2duSNCjIJcF+rFh7j5KaJaTIUoVV8hB5f+a6irv1v381Uzsb69NxLNMI8oo\n' +
'p3DVl59vWL9L87UdbADcokIVg4w+2ost/aEgX/ncsLVJFUIntscAEQEAAYkBPAQY\n' +
'AQgAJhYhBIl2kIV5eydnN/7GUps38F7Q3zvwBQJbQ2gCAhsMBQkDwmcAAAoJEJs3\n' +
'8F7Q3zvwd/oH/ie6fk2SUOn9fkS+Ecp1OA4yUgJ/RGyupEa9BM4yajF5DzDzwaRO\n' +
'4YhRIdY/Fc+tpw1+rERM5j4P3V1AMqmAgxI+oOS0ASdeFfZLfoRv/ryGSTA4XYjk\n' +
'2By/f2foEu9EQZ/wmJRHs78xGB9yN5t8fhOtz8peisEOjjLeDbCDry564RAd+Lwe\n' +
'mtZ5zZCOJKBNNo18bShL5QoskH1mw+FUHn2UTgGCIj/gMPQVhH2lR+j1IbaxApaU\n' +
'PmMhahvlLzHZBhkoVdgMQZftX3/KNF4YB+qOFBgQ+Ye8q5FFZvMQ/RyQU9WzJzoT\n' +
'Ts7NnJ+cc48gZcf8gU7Q4XtmPwK+HwFo9hY=\n' +
'=REGo\n' +
'-----END PGP PUBLIC KEY BLOCK-----\n';

const priv_key_2000_2008 = `-----BEGIN PGP PRIVATE KEY BLOCK-----

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
t/ia1kMpSEiOVLlX5dfHZzhR3WNtBqU=
=C0fJ
-----END PGP PRIVATE KEY BLOCK-----`;

const key_with_authorized_revocation_key = `-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: OpenPGP.js VERSION
Comment: https://openpgpjs.org

xsBNBFujnwwBCADK1xX03tSCmktPDS9Ncij3O5wG+F5/5Zm7QJDc39Wt1t/K
szCSobWtm/UObQVZjsTGwg0ZUPgepgWGGDBL0dlc1NObwUiOhGYnJnd4V25P
iU5Mg3+DhRq+LzNK+oGlpVPDpwQ48S8HOphbswKUpuaDcEQ2f+NKIc0eXe5m
ut5x9uoVj8jneUNsHYq6FIlxh4knzpJWFj5+LNi7plMCwKip6srVNf8He/q0
0xA/4vjSIOfGIE7TCBH33CbHEr98p81Cf4g0E+kswEz5iWE2SDCyYgQkMrkz
H9mtVqk3nFT8NR0USxKqH9bGhaTx1AWq/HDgsphayPEWQ0usjQDrbQUnABEB
AAHNDnRlc3QgPGFAYi5jb20+wsCNBBABCABBBQJbo58MBgsJBwgDAhcMgAH0
cOUNyxrV8eZOCGRKY2E6TW5AlAkQWICi/ReDcrkEFQgKAgMWAgECGQECGwMC
HgEAADgHB/0WIHh6maX2LZ0u5ujk1tZxWMrCycccopdQNKN0RGD98X4fyY6J
wfmKb107gcidJBFct0sVWFW8GU42w9pVMU5qWD6kyFkgcmov319UL+7aZ19b
HOWVKUTb6rFG8/qAbq3BF7YB/cZIBWMFKAS3BRJ4Kz23GheAB2A9oVLmuq5o
gW5c2R1YC0T0XyXEFiw9uZ+AS6kEZymFPRQfPUIbJs1ct/lAN+mC9Qp0Y6CL
60Hd6jlKUb6TgljaQ6CtLfT9v72GeKznapKr9IEtsgYv69j0c/MRM2nmu50c
g+fICiiHrTbNS6jkUz0pZLe7hdhWHeEiqcA9+GC1DxOQCRCS/YNfzsBNBFuj
nwwBCADK1xX03tSCmktPDS9Ncij3O5wG+F5/5Zm7QJDc39Wt1t/KszCSobWt
m/UObQVZjsTGwg0ZUPgepgWGGDBL0dlc1NObwUiOhGYnJnd4V25PiU5Mg3+D
hRq+LzNK+oGlpVPDpwQ48S8HOphbswKUpuaDcEQ2f+NKIc0eXe5mut5x9uoV
j8jneUNsHYq6FIlxh4knzpJWFj5+LNi7plMCwKip6srVNf8He/q00xA/4vjS
IOfGIE7TCBH33CbHEr98p81Cf4g0E+kswEz5iWE2SDCyYgQkMrkzH9mtVqk3
nFT8NR0USxKqH9bGhaTx1AWq/HDgsphayPEWQ0usjQDrbQUnABEBAAHCwF8E
GAEIABMFAlujnwwJEFiAov0Xg3K5AhsMAACI/QgArvTcutod+7n1D8wCwM50
jo3x4KPuQw+NwbOnMbFwv0R8i8NqtSFf2bYkkZ7RLViTmphvSon4h2WgfczL
SBulZ1QZF7zCKXmXDg8/HZgRUflC1XMixpB8Hqouin5AVgMbsbHg30V2uPco
V3DeFQ8HWxQC9symaMW/20MkqNXgCjM0us7kVwTEJQqZ6KYrFVjKyprSQRyP
rfckEBuZnj91OS+kAHlZ+ScZIuV4QVF0e2U6oEuB+qFXppR030PJoO6WDOzm
67hkzfrc3VpKw/I+vVJnZb4GOhNTSpa+p8i4gTyWmrOZ0G85QoldHWlWaRBg
lbjwPj3QUTbLFvHisYzXEQ==
=aT8U
-----END PGP PUBLIC KEY BLOCK-----
`;

const key_with_authorized_revocation_key_in_separate_sig = `-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: CounterMailEngine v1.4

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
=KtVw
-----END PGP PUBLIC KEY BLOCK-----
`;

const key_with_revoked_third_party_cert = `-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: GPGTools - https://gpgtools.org

mQENBFS2KSEBCACzz8KtwE5ualmgF+rKo8aPQ9inTQWCNzCuTs3HaSe0D5heGoSh
mJWl9B5zvXN78L3yzmtWQV92CXOkCRWezIY8y+aN+aJZ6PzPE5Yy74404v3yG9ZK
jGlAWC7Wgkx+YR2vbzj7hDqi5e6TpDGsFkH3OsI3nY7FIvXWbz9Ih4/s/nBPuF0v
sBZ0n97ItszhnrXvvrF1fQvEviB0+xF5DfUURWP45EA+NWnBl7HFzY4FeN5ImYZK
Nt6A88i9SIB3MiwRSUy1UwJjL2L8l+rLbr20JbnIUuJN3h/dY10igxyOh5gsXtr1
fabsm6s2AacrCjQqLkXSnB8Ucu+Enz5R1s0dABEBAAG0KVBhc3N3b3J0ICDDpMOE
Pz9eXjEyIDIgwrUgIDxwd2RAdGVzdC5jb20+iFoEMBEKABoFAlYvilYTHSBJY2gg
d2VpcyBlcyBuaWNodAAKCRDheQpvjBNXTQ5jAKC0AMb5Ivoy0DKNI8Hjus72ob3u
TACg32AGuCernx1Wt7/5oi4KdjxjjxeJATIEEAEIACYFAlS2KSIGCwkIBwMCCRBj
ZJ9T2gveXAQVCAIKAxYCAQIbAwIeAQAA/c4H/i/NgI36q/2lwcRkt5rsVBUlx+Ho
+iKIEh1+XKfDq4A8DTjeYCCOg/k3hDm2LpmmclwRc2X9CMwraSoFTEN6Em78Kd5a
DFaNPbWGP0RCW5zqPGAoZSvOlZYsLMaswFMBD93wf3XwHK8HxTJhTmQC1kGSplO1
GMWkTh6B3tqiy/Jk7Hp5mPASQBid+E9rjr8CgOPF26hjTw+UUBs2ZWO9U9PyhBYH
xLIwtUDoZvqhTdXD0aV7vhRQw6p3UEzxa8t/1iGogHe2CfcMgq5jYmHLTZN3VGE3
djwLQIikRRig7dTBD9BgeG6a+22XRbvpOsHBzsAH4UC97nS+wzkgkyvqfOKIRgQQ
EQoABgUCVi+JYAAKCRDheQpvjBNXTTNIAJwJacb4mKUPrRnnNcGXC6hjizuJOACg
zVFVnWA/A+GrHBogUD780vcJwMG5AQ0EVLYpIQEIANNCJ5sUKv6YDWRToF/tG6ik
LjTAcNelr5LCXLT3Y7CAmk7y88vzCaTLZZUWgwyK8lYGZ3x2icoc4fJeo5BhHNJz
TSL239cTsAugNoVMJFG2xm1TEzBsBCNPOOVpS5cArt6mmhxozwkafawtgA+5z0zB
vQm0AHPudSAJp3Gx69meRzAJgdFVgljZVyCUmQizJqJ1dQPPgarpJKJy3f0+g0ec
yx+gTA4nj+zfqjrXM4O1Ok/Di+8mneA3bhadiYU1VjkqY+1UqkQOU0UFdDlBppRj
xr6h00xECoayyPXr/U+gFSgZHO1mKk3meCyNVKLGAajQxWVWfBwoPixfqOXlBh0A
EQEAAYkBHwQYAQgAEwUCVLYpIwkQY2SfU9oL3lwCGwwAAMkDB/9QeLRyEOX2LWdZ
UkxSldMklAvMBjqY27cC1Qn8wiWzHNJKVEnQ9MiKn0mVRohkRKgsiWfSugDVyVov
eTM7PSjDlAYALCSxSYStykordUSf/5WYb9Mmea4J/WXBQCvwJKFU47ZDl2Tg+HdS
SVznLTt/ASxd2Nap2mUveC4ivGdSo1KOq3+t95xGC7dh4U3JwPanBZ6cfBJbnSEs
QWLUAPnlfn37Ff14haRETX3ND82bkXKEGEk6O5HJ0PWuUtl+TFIkYUGh4zFOZZWq
VHwaffAHDrmTZt/pOXg9l/VFnzfxrId33Tog3Zvejm2+8d2LhSCtfdrdJ/Dx2CZM
Yzxp9Mp9
=uVX6
-----END PGP PUBLIC KEY BLOCK-----
`;

const certifying_key = `-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: GPGTools - https://gpgtools.org

mQGiBEOd+/gRBACfqCfgQCmUzOr7iA1CerGVmFm8HcN+NVGSpkwF6pmPJh1XVGEA
Nz9Aok6Vx4MQ+QCKo9dTXMZWDE4W/vzaKaEmsirsxGgn7JhK0t/9VeXXieWiJirA
5iTQMsRjfnS6MLLUr56E7HmDZftiOcpJu81S943r+oeINhq37SlJM7Q47wCg8miR
egss26IZfW3RvBuNW1KEDh0D/195DH6sl+/qmgUAj3M7ai1iKOqkILdNuIkYRc18
bsBYIAOjY81guhlEabYEqv8FUKPh2A7dAe/4og89HrUsVxOKJ9EGyrcqyJj676gK
BL383t1dQvyJyWfV5z4umUMaF/xE46go3Trdyu86aJDe57B74RYbWL2aaGLtkPJ2
rHOnBACG5PmLM6EXWJQSfbRqJHlRysc3MOAXMnxu8DVz+Tm0nPcArUG+Mf3GmxT+
537nHqF2xEgVvwfkvGB51ideRRQMhHUzy583zkuPYV1cJ6ykfeA6EHzVbT4vRzO8
AW9ELBKTK9F4N4gGTOdAATcaMC0gwzCz+fofJEJqC/9CS2pYvrQlVGhvbWFzIE9i
ZXJuZMO2cmZlciA8dG9iZXJuZG9AZ214LmRlPohdBBMRAgAdBQJDnfv4BgsJCAcD
AgQVAggDBBYCAwECHgECF4AACgkQ4XkKb4wTV02nkACfWvWnRawPI9AmgXpg6jg1
/22exKkAoMJ+yFhjtuGobOrIAPcEYrwlTQXBiGsEEBECACsFAksJKNQFgwHihQAe
Gmh0dHA6Ly93d3cuY2FjZXJ0Lm9yZy9jcHMucGhwAAoJENK7DQFl0P1Y4VoAmgMc
2qWuBtOBb6Uj6DskTtXORlPgAKCB3Hqp8dJ3dbQh5m0Ebf8F3P71WrkCDQRDnfw1
EAgAkp+0jMpfKKF6Gxy63fP3tCFzn9vq3GBtbNnvp8b0dx6nf+ZxELt/q9K4Yz9g
+sXq0RFQGV+YwS2BGoogzRcT4PHmUBcEAbjZIs9lZdZDEF0/68d+32mHSkLZJxGI
ezXJK3+MpGPnCMbQ63UYpcY1BvL7Vbj6P4X75dJJReGIHQMBA0FEYB5AVm6HrWU5
eDvOZ2w8QAAUluFnD9/xNRqBpcwm5uoox7zq60W5coK6p6WX8t5+WMMrRKF2A1Ru
aTxYQKo3f8XQA4e6tEcdGFlk1K9W8Ov1xVRQa6EqQYZFesbuoo8HHuSNsJ7PQrP+
vyYcafohlO/q4QtJXoUimsrEywADBQf7BQWrEx9YlNNsUD2yuov8pYCymxfUVTzK
huxGHmNj1htXfWWScA2uqD97HOdFu5nvoL2tdaO1RQR/OXKRBcUg6FhOQqqxQSxi
Vcsoy3aofGi3CWVXgn7KlSopkhlb4ELjzt5H+BMneXdgowO4MimXAfivI7OZl2fN
ut7emyN9qaeY/e25UKmCYhmhE5hM2+lV8wEmmu/qTCPiZ2u0zH/PE9AAwRz/6X+p
gsW0WIQpI6iQSSq4KyJxebtJFmCSTFawuXB6rCGovDXo/BkRsDEj1rpZnkwKJPa0
dEhKK4EzNrUzpWHeE3gKPjFXVmcjIPWVAC3BJoJRHOHg8wqLKcX5MYhGBBgRAgAG
BQJDnfw1AAoJEOF5Cm+ME1dNChoAoMKa/qx/RKlu3iQPtN6p4NlhRA9IAJ94F/7l
cKFQz1DDfFCfVpSIJRGozQ==
=EYzO
-----END PGP PUBLIC KEY BLOCK-----
`;

/* const revoked_primary_user = `-----BEGIN PGP PUBLIC KEY BLOCK-----

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
=qfwW
-----END PGP PUBLIC KEY BLOCK-----
`; */

const key_created_2030 = `-----BEGIN PGP PUBLIC KEY BLOCK-----

xsBNBHEtJEoBCAC5eMNNia6oZJI7llva4L9/O9/TXd5HZt95hbXCBHr5BTmD
VDHNYXCpi7L+1qTDJqaAHY/GyeSgiAeFOEKOiyFXhdSgiLmru4DLtp+6cg8C
AiJR/V/GzN5vtSL7JuQu8LOzYZnPzoNtM9i5P1c0MqTguP9HMSuF+kqId+q5
siZK+YqZPH0VHNDHOe31ulNeC9jRTaiafg5m0zkI3Go4wRoCt6CzO+hQJ6u+
knHBQ2YfDBX2PtXn77CAGLgh2heX2Abd1LvvweMlDzqYFhwk+dHEUT8DA0rl
vJwuOiNAkfRhC4nwtLhikvlOs6Uh8hrblxuab2kTwYsPFawQR5wPEPsJABEB
AAHNIkNyZWF0ZWQgaW4gMjAzMCA8Y3JlYXRlZEAyMDMwLm9yZz7CwHUEEAEI
AB8FAnEtJEoGCwkHCAMCBBUICgIDFgIBAhkBAhsDAh4BAAoJEFuE0AYFWFcL
K8MIAJAowJs1PY10ChPvcoVNDtgO23eXLi1C1x3IBeV2l2JtwvJ8ZTTCiKF/
IdPIsxKhV39pebFip3hIsjSYCF3SlkGht8XiJBVamsNtXhfY0JB6mkKntVBA
4OiQ7Aa94mq7nvEwFtwS3W7Wdf8R5BlWTADPwKkXFj3/G7pHy1HiQ/+6xL0U
RkH57QUsl73IgAH5XaoXbhgvuCD66kQBoSkG6NFh/EUuwHkv6PEAcczGhsr5
ewDH4+XxhGKY9X71CrVAR5V0UoC3MJM1MNgvkSycciZsz/1oRiWSl7XWChGe
tlOn21ImIkRmHC4ev3BbbGWiI4WNWmQ9Tm/2Qt/hkAQbOZ3OwE0EcS0kSgEI
ALSV5Z3NSBV/nftJzYJ7VVWzlzxAMQODj+iWpD28XqchslF0+xS4LVMDvoG7
Sa6RoHq6muMG+pcP0ho7kpPvXc5LEjhYvOdbdaRWqxBoywAzvMZga+u1vKsy
087xgmffASkFPqwPDkuOMQ7LSG16NGMDKZGubfdKy+FY+AcL1Cnc76LgEixR
DPuLZyPRVUOmPWPoEebbHfQRYQpZmEbDY6D3XECm6yM1BlbvL0+SAksP2Ib+
g9f4NFbXGWVaKYflifbUcnXi5+xZdt4D0k56eySl26Rz0ojt7hzY7d+V/zEm
KxoHT5OvXV5BV0B/e/nSrOIyQkhTGejON14lOtFV5WsAEQEAAcLAXwQYAQgA
CQUCcS0kSgIbDAAKCRBbhNAGBVhXC2SqCACJovJpZJTKDBXfRvNMRO2LdTpC
lAkm9RyBjQ4BGxoqEaXtxJAOyKjDzvD6+zwlJwAWSM4j2oYsaZsSosASfXHj
kcy5HTRP6MN6pcBnNPlJIlOqVdzqMCStLnFrYpsvl7xD3VrfOOz9gTuZl/n9
GbziMjGUES8PK63IR/JKI4iNKD9M3xLkHOFjyxHG17AlHPHBdtb7DvKg780H
Sh4BCGqNrB0ikvMCZwZBpIAck4BGXPeuykFQ93BxCsbVdXIKqK44g5+hG2Bg
iCzXvu4VCEMxMYOkOV4857v958DC7Z7W6BYEYpa9DP0O2zAwDmhu/kRFfKVQ
3GOWvBNGqRPrEJ49
=JOnb
-----END PGP PUBLIC KEY BLOCK-----
`;

const v5_sample_key = `-----BEGIN PGP PRIVATE KEY BLOCK-----

lGEFXJH05BYAAAAtCSsGAQQB2kcPAQEHQFhZlVcVVtwf+21xNQPX+ecMJJBL0MPd
fj75iux+my8QAAAAAAAiAQCHZ1SnSUmWqxEsoI6facIVZQu6mph3cBFzzTvcm5lA
Ng5ctBhlbW1hLmdvbGRtYW5AZXhhbXBsZS5uZXSIlgUTFggASCIhBRk0e8mHJGQC
X5nfPsLgAA7ZiEiS4fez6kyUAJFZVptUBQJckfTkAhsDBQsJCAcCAyICAQYVCgkI
CwIEFgIDAQIeBwIXgAAA9cAA/jiR3yMsZMeEQ40u6uzEoXa6UXeV/S3wwJAXRJy9
M8s0AP9vuL/7AyTfFXwwzSjDnYmzS0qAhbLDQ643N+MXGBJ2BZxmBVyR9OQSAAAA
MgorBgEEAZdVAQUBAQdA+nysrzml2UCweAqtpDuncSPlvrcBWKU0yfU0YvYWWAoD
AQgHAAAAAAAiAP9OdAPppjU1WwpqjIItkxr+VPQRT8Zm/Riw7U3F6v3OiBFHiHoF
GBYIACwiIQUZNHvJhyRkAl+Z3z7C4AAO2YhIkuH3s+pMlACRWVabVAUCXJH05AIb
DAAAOSQBAP4BOOIR/sGLNMOfeb5fPs/02QMieoiSjIBnijhob2U5AQC+RtOHCHx7
TcIYl5/Uyoi+FOvPLcNw4hOv2nwUzSSVAw==
=IiS2
-----END PGP PRIVATE KEY BLOCK-----
`;

const mismatchingKeyParams = `-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: OpenPGP.js v4.7.0
Comment: https://openpgpjs.org

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
0NubenKyljKtyHyoU+S+TqUyx7gf5A==
=Lj9k
-----END PGP PRIVATE KEY BLOCK-----
`;

const gnuDummyKeySigningSubkey = `
-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: OpenPGP.js VERSION
Comment: https://openpgpjs.org

xZUEWCC+hwEEALu8GwefswqZLoiKJk1Nd1yKmVWBL1ypV35FN0gCjI1NyyJX
UfQZDdC2h0494OVAM2iqKepqht3tH2DebeFLnc2ivvIFmQJZDnH2/0nFG2gC
rSySWHUjVfbMSpmTaXpit8EX/rjNauGOdbePbezOSsAhW7R9pBdtDjPnq2Zm
vDXXABEBAAH+B2UAR05VAc0JR05VIER1bW15wrgEEwECACIFAlggvocCGwMG
CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEJ3XHFanUJgCeMYD/2zKefpl
clQoBdDPJKCYJm8IhuWuoF8SnHAsbhD+U42Gbm+2EATTPj0jyGPkZzl7a0th
S2rSjQ4JF0Ktgdr9585haknpGwr31t486KxXOY4AEsiBmRyvTbaQegwKaQ+C
/0JQYo/XKpsaX7PMDBB9SNFSa8NkhxYseLaB7gbM8w+Lx8EYBFggvpwBBADF
YeeJwp6MAVwVwXX/eBRKBIft6LC4E9czu8N2AbOW97WjWNtXi3OuM32OwKXq
vSck8Mx8FLOAuvVq41NEboeknhptw7HzoQMB35q8NxA9lvvPd0+Ef+BvaVB6
NmweHttt45LxYxLMdXdGoIt3wn/HBY81HnMqfV/KnggZ+imJ0wARAQABAAP7
BA56WdHzb53HIzYgWZl04H3BJdB4JU6/FJo0yHpjeWRQ46Q7w2WJzjHS6eBB
G+OhGzjAGYK7AUr8wgjqMq6LQHt2f80N/nWLusZ00a4lcMd7rvoHLWwRj80a
RzviOvvhP7kZY1TrhbS+Sl+BWaNIDOxS2maEkxexztt4GEl2dWUCAMoJvyFm
qPVqVx2Yug29vuJsDcr9XwnjrYI8PtszJI8Fr+5rKgWE3GJumheaXaug60dr
mLMXdvT/0lj3sXquqR0CAPoZ1Mn7GaUKjPVJ7CiJ/UjqSurrGhruA5ikhehQ
vUB+v4uIl7ICcX8zfiP+SMhWY9qdkmOvLSSSMcTkguMfe68B/j/qf2en5OHy
6NJgMIjMrBHvrf34f6pxw5p10J6nxjooZQxV0P+9MoTHWsy0r6Er8IOSSTGc
WyWJ8wmSqiq/dZSoJcLAfQQYAQIACQUCWCC+nAIbAgCoCRCd1xxWp1CYAp0g
BBkBAgAGBQJYIL6cAAoJEOYZSGiVA/C9CT4D/2Vq2dKxHmzn/UD1MWSLXUbN
ISd8tvHjoVg52RafdgHFmg9AbE0DW8ifwaai7FkifD0IXiN04nER3MuVhAn1
gtMu03m1AQyX/X39tHz+otpwBn0g57NhFbHFmzKfr/+N+XsDRj4VXn13hhqM
qQR8i1wgiWBUFJbpP5M1BPdH4Qfkcn8D/j8A3QKYGGETa8bNOdVTRU+sThXr
imOfWu58V1yWCmLE1kK66qkqmgRVUefqacF/ieMqNmsAY+zmR9D4fg2wzu/d
nPjJXp1670Vlzg7oT5XVYnfys7x4GLHsbaOSjXToILq+3GwI9UjNjtpobcfm
mNG2ibD6lftLOtDsVSDY8a6a
=KjxQ
-----END PGP PRIVATE KEY BLOCK-----
`;

const gnuDummyKey = `
-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: OpenPGP.js VERSION
Comment: https://openpgpjs.org

xZUEWCC+hwEEALu8GwefswqZLoiKJk1Nd1yKmVWBL1ypV35FN0gCjI1NyyJX
UfQZDdC2h0494OVAM2iqKepqht3tH2DebeFLnc2ivvIFmQJZDnH2/0nFG2gC
rSySWHUjVfbMSpmTaXpit8EX/rjNauGOdbePbezOSsAhW7R9pBdtDjPnq2Zm
vDXXABEBAAH+B2UAR05VAc0JR05VIER1bW15wrgEEwECACIFAlggvocCGwMG
CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEJ3XHFanUJgCeMYD/2zKefpl
clQoBdDPJKCYJm8IhuWuoF8SnHAsbhD+U42Gbm+2EATTPj0jyGPkZzl7a0th
S2rSjQ4JF0Ktgdr9585haknpGwr31t486KxXOY4AEsiBmRyvTbaQegwKaQ+C
/0JQYo/XKpsaX7PMDBB9SNFSa8NkhxYseLaB7gbM8w+L
=yGSn
-----END PGP PRIVATE KEY BLOCK-----
`;

const eddsaKeyAsEcdsa = `
-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: OpenPGP.js VERSION
Comment: https://openpgpjs.org

xVgEXseu0BMJKwYBBAHaRw8BAQdA7MOW/AQa3aDGJJw9upY2Qv4cxv4MQHr5
81xmFwvyf+EAAQC0bOQsFDKCdAQ4cACKqbSDO2st+V9s3bEmSZV+fVR6ww44
zRFib2IgPGJvYkBib2IuY29tPsJ3BBATCgAgBQJex69xBgsJBwgDAgQVCAoC
BBYCAQACGQECGwMCHgEACgkQInpzQil4KrkPrQD7BkYxgDzyrfynM8mUSEdr
4iOivzbGo9zmn7cwluO2LI4A9iCJG4Xao9VFlyOAizVzNWlhfptwWVH5awh4
YFDlUSbHXQRex67QEgorBgEEAZdVAQUBAQdAI5fo7gn4y8IybTJ1m+xn90Xs
uqlIEDirKMx7WVJ/2QcDAQgHAAD/cPduuCXzoLkEI6Po4kTfoWXC6w6AEyGg
LA+BABNTPIAPp8JhBBgTCAAJBQJex69xAhsMAAoJECJ6c0IpeCq5D7EA/Ajk
xCrUtYPsmEDcr+1TFQCoOFGEKiYG6wNeuTaLqvPjAPsH8p3BnYBqlELdHU2I
9RFfjwPHLd+fZMQC6+mEaRJ4AA==
=2b6I
-----END PGP PRIVATE KEY BLOCK-----
`;

const dsaGnuDummyKeyWithElGamalSubkey = `-----BEGIN PGP PRIVATE KEY BLOCK-----

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
vqBGKJzmO5q3cECw
=X9kJ
-----END PGP PRIVATE KEY BLOCK-----`;

const dsaPrivateKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----

lQNTBF69PO8RCACHP4KLQcYOPGsGV9owTZvxnvHvvrY8W0v8xDUL3y6CLc05srF1
kQp/81iUfP5g57BEiDpJV95kMh+ulBthIOGnuMCkodJjuBICB4K6BtFTV4Fw1Q5S
S7aLC9beCaMvvGHXsK6MbknYl+IVJY7Zmml1qUSrBIQFGp5kqdhIX4o+OrzZ1zYj
ALicqzD7Zx2VRjGNQv7UKv4CkBOC8ncdnq/4/OQeOYFzVbCOf+sJhTgz6yxjHJVC
fLk7w8l2v1zV11VJuc8cQiQ9g8tjbKgLMsbyzy7gl4m9MSCdinG36XZuPibZrSm0
H8gKAdd1FT84a3/qU2rtLLR0y8tCxBj89Xx/AQCv7CDmwoU+/yGpBVVl1mh0ZUkA
/VJUhnJfv5MIOIi3AQf8CS9HrEmYJg/A3z0DcvcwIu/9gqpRLTqH1iT5o4BCg2j+
Cog2ExYkQl1OEPkEQ1lKJSnD8MDwO3BlkJ4cD0VSKxlnwd9dsu9m2+F8T+K1hoA7
PfH89TjD5HrEaGAYIdivLYSwoTNOO+fY8FoVC0RR9pFNOmjiTU5PZZedOxAql5Os
Hp2bYhky0G9trjo8Mt6CGhvgA3dAKyONftLQr9HSM0GKacFV+nRd9TGCPNZidKU8
MDa/SB/08y1bBGX5FK5wwiZ6H5qD8VAUobH3kwKlrg0nL00/EqtYHJqvJ2gkT5/v
h8+z4R4TuYiy4kKF2FLPd5OjdA31IVDoVgCwF0WHLgf/X9AiTr/DPs/5dIYN1+hf
UJwqjzr3dlokRwx3CVDcOVsdkWRwb8cvxubbsIorvUrF02IhYjHJMjIHT/zFt2zA
+VPzO4zabUlawWVepPEwrCtXgvn9aXqjhAYbilG3UZamhfstGUmbmvWVDadALwby
EO8u2pfLhI2lep63V/+KtUOLhfk8jKRSvxvxlYAvMi7sK8kB+lYy17XKN+IMYgf8
gMFV6XGKpdmMSV3jOvat8cI6vnRO0i+g3jANP3PfrFEivat/rVgxo67r4rxezfFn
J29qwB9rgbRgMBGsbDvIlQNV/NWFvHy2uQAEKn5eX4CoLsCZoR2VfK3BwBCxhYDp
/wAA/0GSmI9MlMnLadFNlcX2Bm4i15quZAGF8JxwHbj1dhdUEYq0E1Rlc3QgPHRl
c3RAdGVzdC5pbz6IlAQTEQgAPBYhBAq6lCI5EfrbHP1qZCxnOy/rlEGVBQJevTzv
AhsDBQsJCAcCAyICAQYVCgkICwIEFgIDAQIeBwIXgAAKCRAsZzsv65RBlUPoAP9Q
aTCWpHWZkvZzC8VU64O76fHp31rLWlcZFttuDNLyeAEAhOxkQHk6GR88R+EF5mrn
clr63t9Q4wreqOlO0NR5/9k=
=UW2O
-----END PGP PRIVATE KEY BLOCK-----
`;

const uidlessKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----

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
CciXuhqnLwoVF5/uXMYffVtfl/OU+w==
=EqcV
-----END PGP PRIVATE KEY BLOCK-----`;

const rsaSignOnly = `-----BEGIN PGP PRIVATE KEY BLOCK-----

xcLYBF9Gl+MBCACc09O3gjyO0B1ledGxGFSUpPmhhJzkxKoY1WDX8VlASCHz
bAA/BytgYBXHTe7N+N3yJ6uiN3DIQ2j5uGWk/h5jyIOsRuzQxJ40n8AdK/71
SGDCG1X5l1h9vmVTJxkQ3pcOxqRg55EEuJWKN1v7B1hIPxhaM5hgH/7s+PNn
lQddckQJqYkpm9Hy6EI7f9oHrOtWJWZoCHkWZVld7+9ZVPi34ex5ofYOuvNL
AIKZCc7lAiUiDJYQ+hIJRoYwLYhjIshpYoHgNeG4snlupNO32BiwDbHFDjeu
eoBLQ0rxZV7B664ceCmIl+VRht9G20hfGoTjAiop5tyrN1ZeL4EaI+aTABEB
AAEAB/oCKTQnftvHwrkBVlyzSN6tfXylF2551Q3n4CZGg3efI/9PCa9wF58+
WApqmgsUqcNbVnDfl2T58ow05FLMxnFFNnHJq8ltfnXl+gG6c7iy94p79SQE
AGCOL7xNassXrDAQZhqWkCdiLK3b6r9F8Y3URb/AYbWH2BkFkS0oWQDav+Tw
lABt5vG2L5QtnShdqi8CCitcHGEKHocPHp0yAQlp3oAMq09YubgrzESDJ7Pe
l93cT35NlyimAZ6IYk/gumX0/6spqcw7205KfG6P84WlMp3WmE0IUWtiOp+7
rjMjDki0WeVKtuLbHBhOwKvxcILWz+0vQf3uu6aXOKQ3JlsVBADHoXa6QjrT
RmKD9ch65Pkd+EZiKhe+pqqIArVj4QsVBEnaggR59SD8uXhtpyBnvOp3xpof
Vut3SKWl/jmH7vKansFbHOo8xLUyVctu7lCL2/v85FcRJxfPK00MBic+z/vf
mWOAY1VBoi5I9qi6o8vVHA5BJ/xw2uV9VpxfiLG0vwQAyRxHmoZl/OxaZUsm
J9eDYV9xyYumkTCYvHPk9X+ehS+XeYh24z1q9a/1jEnSR3A5XE67UCLaspiA
+Px7nSU1+ftJ9bC2bnRR0Upop+3UkPeCBVp4tYAhsNnPXhSWC0gCgeGU7EmW
DechFg29LId35LXKgmXls9u5yDy2w978Hy0D/jbKZaxNMMwlx/XCFCoBEcXS
DBzg7GHNXdillJqy215j46lfVqOCB3IiffNKjHua2l6fQc0BoiWIZnElMnIa
faEBBSpOVqKhktDFacHa5xChjqXZVyw68qc0I36xkCfcwvYCpNKKkXv90r8A
tRI6gpBLeMJvkL3VkmKd6AZymxFxRGjNEkJvYiA8aW5mb0Bib2IuY29tPsLA
jQQQAQgAIAUCX0aX4wYLCQcIAwIEFQgKAgQWAgEAAhkBAhsDAh4BACEJEAr9
x5ZY6oZmFiEEm+B7p+lshgEOwGGZCv3HlljqhmaUWgf/efmGSpOKIGQ3Kh32
HUqn/4ARvUmqMtZz4xUA9P3GAPY8XwJf00jSQlAo4//3aA1eEOJFHCr2qzCk
/4gIoZEScTTZp4itfL/Fer3UX+bV/VeTNgZGi+MRylSDQxLRQNpRgu+FmRAi
E6fr8D8GMvEcGb0jTRgWGj1EVtfOHfDg+EyPrtw+Z8u/bErUJ+Fnxz+KOGSN
SBQVAOflUYFoQhUNgZiq1s8WFD55sfes3UdBwsmHquDtYGo9dvWLJXxTEF8q
QCyKHYdk25ShIlNpRUqOH3CHqY/38z7QeV7INwtZaQvoES08RlD6ZMtczYLj
BZou86lozq7ISvRg1RSIWZ0ZRA==
=A9Ts
-----END PGP PRIVATE KEY BLOCK-----
`;

const encryptedRsaSignOnly = `-----BEGIN PGP MESSAGE-----

wcBMAwr9x5ZY6oZmAQf+Lxghg4keIFpEq8a65gFkIfW+chHTDPlfI8xnx6U9
HdsICX3Oye5V0ToCVKkEWDxfN1yCfXiYalSNo7ScRZKR7C+j02/pC+FfR6AJ
2cvdFoGIrLaXdjXXc/oXbsCCZA4C1DhQqpdORo2qGF0Q6Sm8659B0CfOgYSL
fBfKQ5VJngUT5JG8Uek3YuXBufPNhzdmXLHyB2Y2CwKkldi2vo4YNAukDhrR
2TojxdNoouhnMm+gloCE1n8huY1vw5F78/uiHen0tmHQ0dxtfk8cc1burgl/
zUdJ3Sg6Eu+OC2ae5II63iB5fG+lCwZtfuepWnePDv8RDKNHCVP/LoBNpGOZ
U9I6AUkZWdcsueib9ghKDDy+HbUbf2kCJWUnuyeOCKqQifDb8bsLmdQY4Wb6
EBeLgD8oZHVsH3NLjPakPw==
=STqy
-----END PGP MESSAGE-----`;

const shortP521Key = `-----BEGIN PGP PRIVATE KEY BLOCK-----

xcAiBV/Pa+4TAAAAjQUrgQQAIwQjBADY+IGvRpeUzbT0+YRUe0KCMxAZmDY1
KjDzULlmOJOS0bfZfqd4HsUF2hRoU/rg1gu1ju/Nt/18db0SJExOqVB9CgA0
ZYiYyJhGYDOVg/bD54E7a3txWuDPB1DzkGWJH8PkqGNzU0BJpZcUVA6Th09s
YeO7rx5jSoyWNXjUYKwc24trFAAAAAAARQIItVgIiTWNT+QEVnZqDKKTIOUU
XEetkjCjPed1RiSchiZpwq+Bvx5hWGsbV5Pjj0S6EuH/ca5w+2ZyITLWZjr1
LP8eP80UVGVzdCA8dGVzdEB0ZXN0LmNvbT7CwBUFEBMKACEFAl/Pa+4ECwkH
CAMVCAoEFgIBAAIZAQIbAwIeBwMiAQIAIyIhBbDerrGG7kdy9vbLYvb/j6TC
53fuQgK9Gtt1xng5MgpSUX0CCJZB+Ppt8yG5hBzwiGz5ZRpPVBFihEftaTOO
tKUuYRpWlvgA/XV11DgL6KZWRwu4C2venydBW987CVXCbRp4r18FAgkBjTR1
AXHEstTVwJYj8mWkOZrz+Bfqvu6pWPmVYclgHJK2sSWizakvX/DtX/LFgTJL
UoASOVvu1hYHDsCO7vWWC/bHwCYFX89r7hIAAACRBSuBBAAjBCMEAULqNQ3L
CcdVlpIHiq4Xb+elTEdu2oDDA+FCbwroX3wvMatrH6GodxCcrjQKUrfVNiiI
cvj+r6SE/pRDnxsvW/JSAWUz3XKfVXccb0PYf0ikkTmb8UW33AaNYX6Srk0W
iamEmEzUpCMiiyXiYe+fp9JD63rKLXBbvLCT2mHuYO/hOikKAwEKCQAAAAAA
RQIDBONtE8bb3Yr2otNhdR67lg529mm3rSRsyWwMBVUPwX0RTTZ/bejq7XP5
fuXV8QSEjWdOdPBARGw9jhw51D1XWl8gFsK9BRgTCgAJBQJfz2vuAhsMACMi
IQWw3q6xhu5Hcvb2y2L2/4+kwud37kICvRrbdcZ4OTIKUiWwAgkBdH+OZHBt
D2Yx2xKVPqDGJgMa5Ta8GmQZOFnoC2SpB6i9hIOfwiNjNLs+bv+kTxZ09nzf
3ZUGYi5Ei70hLrDAy7UCCNQNObtPmUYaUTtRzj3S9jUohbIpQxcfyoCMh6aP
usLw5q4tc+I5gdq57aiulJ8r4Jj9rdzsZFA7PzNJ9WPGVYJ3
=GSXO
-----END PGP PRIVATE KEY BLOCK-----`;

const expiredPublicKeyThroughDirectSignature = `-----BEGIN PGP PUBLIC KEY BLOCK-----

xsDNBF2lnPIBDAC5cL9PQoQLTMuhjbYvb4Ncuuo0bfmgPRFywX53jPhoFf4Zg6mv
/seOXpgecTdOcVttfzC8ycIKrt3aQTiwOG/ctaR4Bk/t6ayNFfdUNxHWk4WCKzdz
/56fW2O0F23qIRd8UUJp5IIlN4RDdRCtdhVQIAuzvp2oVy/LaS2kxQoKvph/5pQ/
5whqsyroEWDJoSV0yOb25B/iwk/pLUFoyhDG9bj0kIzDxrEqW+7Ba8nocQlecMF3
X5KMN5kp2zraLv9dlBBpWW43XktjcCZgMy20SouraVma8Je/ECwUWYUiAZxLIlMv
9CurEOtxUw6N3RdOtLmYZS9uEnn5y1UkF88o8Nku890uk6BrewFzJyLAx5wRZ4F0
qV/yq36UWQ0JB/AUGhHVPdFf6pl6eaxBwT5GXvbBUibtf8YI2og5RsgTWtXfU7eb
SGXrl5ZMpbA6mbfhd0R8aPxWfmDWiIOhBufhMCvUHh1sApMKVZnvIff9/0Dca3wb
vLIwa3T4CyshfT0AEQEAAcLA+QQfAQoADAWCX2i/SgWJAT9MWAAhCRD7/MgqAV5z
MBYhBNGmbhojsYLJmA94jPv8yCoBXnMwZNYL/RmU7kIYsi7w8d7sPLiqb5C9fs9k
TJuxLREYpKE7zWz9z16+c9ketkoLpoMSDaZL+4+QEfyAJA+q8c8ZFHJ8E60cPNwe
jN/ZI+vJRloDAfxMkH+BdKshMtvcmlLq2+AbQWzT0kAUkiiKiUiUsQwrTfenjkT5
FCsZyKviLsarzdIhpwEdd6zCxWQDap55njXfpUh/vQFZo4aHHtWPwXXRjLZRlKA+
gI8LQyYuIFOCFQMrhZVEwaLJQa6IbauL4B/qD4y5AMenNumW5M06p0G8yj1L22b6
R2hWS7Ueo0iu9J4abTEDo1gGxeLwCiMRUGpN7L+4J3yrzGNcjjtXz1/FT6/YSvT2
bnPraOOGaEO5tflQZ6plEOIc9bKnb2vySlwpxnWgJ7CQdAT+lGVT5xRZ//we5yja
vsb4pdo0xIW32YDzFQ36HgAO8XUXnz0NkgVDHLujWsyhjq9xkfMOhSmGSeXxvsXa
1O9uC2n+qX8hV7whWf20UPHKatYbBV0HHJeA280hQm9iIEJhYmJhZ2UgPGJvYkBv
cGVucGdwLmV4YW1wbGU+wsEOBBMBCgA4AhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4B
AheAFiEE0aZuGiOxgsmYD3iM+/zIKgFeczAFAl2lnvoACgkQ+/zIKgFeczBvbAv/
VNk90a6hG8Od9xTzXxH5YRFUSGfIA1yjPIVOnKqhMwps2U+sWE3urL+MvjyQRlyR
V8oY9IOhQ5Esm6DOZYrTnE7qVETm1ajIAP2OFChEc55uH88x/anpPOXOJY7S8jbn
3naC9qad75BrZ+3g9EBUWiy5p8TykP05WSnSxNRt7vFKLfEB4nGkehpwHXOVF0CR
NwYle42bg8lpmdXFDcCZCi+qEbafmTQzkAqyzS3nCh3IAqq6Y0kBuaKLm2tSNUOl
ZbD+OHYQNZ5Jix7cZUzs6Xh4+I55NRWl5smrLq66yOQoFPy9jot/Qxikx/wP3MsA
zeGaZSEPc0fHp5G16rlGbxQ3vl8/usUV7W+TMEMljgwd5x8POR6HC8EaCDfVnUBC
Pi/Gv+egLjsIbPJZZEroiE40e6/UoCiQtlpQB5exPJYSd1Q1txCwueih99PHepsD
hmUQKiACszNU+RRozAYau2VdHqnRJ7QYdxHDiH49jPK4NTMyb/tJh2TiIwcmsIpG
zsDNBF2lnPIBDADWML9cbGMrp12CtF9b2P6z9TTT74S8iyBOzaSvdGDQY/sUtZXR
g21HWamXnn9sSXvIDEINOQ6A9QxdxoqWdCHrOuW3ofneYXoG+zeKc4dC86wa1TR2
q9vW+RMXSO4uImA+Uzula/6k1DogDf28qhCxMwG/i/m9g1c/0aApuDyKdQ1PXsHH
Nlgd/Dn6rrd5y2AObaifV7wIhEJnvqgFXDN2RXGjLeCOHV4Q2WTYPg/S4k1nMXVD
wZXrvIsA0YwIMgIT86Rafp1qKlgPNbiIlC1g9RY/iFaGN2b4Ir6GDohBQSfZW2+L
XoPZuVE/wGlQ01rh827KVZW4lXvqsge+wtnWlszcselGATyzqOK9LdHPdZGzROZY
I2e8c+paLNDdVPL6vdRBUnkCaEkOtl1mr2JpQi5nTU+gTX4IeInC7E+1a9UDF/Y8
5ybUz8XV8rUnR76UqVC7KidNepdHbZjjXCt8/Zo+Tec9JNbYNQB/e9ExmDntmlHE
sSEQzFwzj8sxH48AEQEAAcLA9gQYAQoAIBYhBNGmbhojsYLJmA94jPv8yCoBXnMw
BQJdpZzyAhsMAAoJEPv8yCoBXnMw6f8L/26C34dkjBffTzMj5Bdzm8MtF67OYneJ
4TQMw7+41IL4rVcSKhIhk/3Ud5knaRtP2ef1+5F66h9/RPQOJ5+tvBwhBAcUWSup
KnUrdVaZQanYmtSxcVV2PL9+QEiNN3tzluhaWO//rACxJ+K/ZXQlIzwQVTpNhfGz
AaMVV9zpf3u0k14itcv6alKY8+rLZvO1wIIeRZLmU0tZDD5HtWDvUV7rIFI1WuoL
b+KZgbYn3OWjCPHVdTrdZ2CqnZbG3SXw6awH9bzRLV9EXkbhIMez0deCVdeo+wFF
klh8/5VK2b0vk/+wqMJxfpa1lHvJLobzOP9fvrswsr92MA2+k901WeISR7qEzcI0
Fdg8AyFAExaEK6VyjP7SXGLwvfisw34OxuZr3qmx1Sufu4toH3XrB7QJN8Xyqqbs
GxUCBqWif9RSK4xjzRTe56iPeiSJJOIciMP9i2ldI+KgLycyeDvGoBj0HCLO3gVa
Be4ubVrj5KjhX2PVNEJd3XZRzaXZE2aAMQ==
=ZeAz
-----END PGP PUBLIC KEY BLOCK-----`;

const keyWithImageData = `-----BEGIN PGP PUBLIC KEY BLOCK-----

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
=kUWS
-----END PGP PUBLIC KEY BLOCK-----`;

// key encrypted with invalid s2kType = 23, to test that it can still be used for encryption/verification
const encryptedKeyUnknownS2K = `-----BEGIN PGP PRIVATE KEY BLOCK-----

xYYEZJ2H3RYJKwYBBAHaRw8BAQdA3V39Xv0+436Rpn/2UlcnOC1BGprmAlWY
RBKjAq0hAtD+CRcIdHzwqoLa54cAbBOEIgBh7Xa1Qh5wCGAmEVWnAldaqvk+
NcvUL2bR6AQsGIT6YEihOS3xLKobMOd2XlO5ItQoWnONzkWgzjFvctgnlhmq
I80AwowEEBYKAD4FgmSdh90ECwkHCAmQaBT7gxSTsXwDFQgKBBYAAgECGQEC
mwMCHgEWIQSvRnJTQT6TtdZFk0NoFPuDFJOxfAAAT7kBALmmUEJt5HMAOWiW
7/8y4wllm8zNQ9vbl5Q0cWbeWj/8AP9HDa2rRxHY/37g5zXdmL9f/qNWr9Fk
EBRhLLwusumuDMeLBGSdh90SCisGAQQBl1UBBQEBB0Am2yjjialeIVXHJJ2P
b7KiapCC0mD95F0EFz6zz0l4DgMBCAf+CRcISMdt0OUFCNUABB/OD0UW7MPK
Y3t8RrUTYoiCuhuPRDLOJ5NnMNagVQLt3jQsI8JRjzmYbiTrA/V3iJIEDu5C
NWbnvCM7Hs7+OqPzJPJ2w8J4BBgWCAAqBYJknYfdCZBoFPuDFJOxfAKbDBYh
BK9GclNBPpO11kWTQ2gU+4MUk7F8AADwfwD8CsOVw/3zm1UwUbGUi+fuf6Pr
VFBLG8uc9IiaKann/DYBAJcZNZHRSfpDoV2pUA5EAEi2MdjxkRysFQnYPRAu
0pYO
=rWL8
-----END PGP PRIVATE KEY BLOCK-----`;

function versionSpecificTests() {
  it('Preferences of generated key', function() {
    const testPref = function(key) {
      const selfSignature = openpgp.config.v6Keys ? key.directSignatures[0] : key.users[0].selfCertifications[0];
      // key flags
      const keyFlags = openpgp.enums.keyFlags;
      expect(selfSignature.keyFlags[0] & keyFlags.certifyKeys).to.equal(keyFlags.certifyKeys);
      expect(selfSignature.keyFlags[0] & keyFlags.signData).to.equal(keyFlags.signData);
      expect(key.subkeys[0].bindingSignatures[0].keyFlags[0] & keyFlags.encryptCommunication).to.equal(keyFlags.encryptCommunication);
      expect(key.subkeys[0].bindingSignatures[0].keyFlags[0] & keyFlags.encryptStorage).to.equal(keyFlags.encryptStorage);
      const sym = openpgp.enums.symmetric;
      expect(selfSignature.preferredSymmetricAlgorithms).to.eql([sym.aes256, sym.aes128]);
      if (openpgp.config.aeadProtect) {
        const aead = openpgp.enums.aead;
        expect(selfSignature.preferredCipherSuites).to.eql([
          [sym.aes256, aead.gcm],
          [sym.aes128, aead.gcm],
          [sym.aes256, aead.eax],
          [sym.aes128, aead.eax],
          [sym.aes256, aead.ocb],
          [sym.aes128, aead.ocb]
        ]);
      }
      const hash = openpgp.enums.hash;
      expect(selfSignature.preferredHashAlgorithms).to.eql([hash.sha512, hash.sha256, hash.sha3_512, hash.sha3_256]);
      const compr = openpgp.enums.compression;
      expect(selfSignature.preferredCompressionAlgorithms).to.eql([compr.uncompressed, compr.zlib, compr.zip]);

      let expectedFeatures = 0x01; // SEIPDv1
      if (openpgp.config.aeadProtect) {
        expectedFeatures |= 0x08; // SEIPDv2
      }
      expect(selfSignature.features).to.eql([expectedFeatures]);
    };
    const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: 'hello', format: 'object' };
    return openpgp.generateKey(opt).then(({ privateKey, publicKey }) => {
      testPref(privateKey);
      testPref(publicKey);
    });
  });

  it('Preferences of generated key - with config values', async function() {
    const preferredSymmetricAlgorithmVal = openpgp.config.preferredSymmetricAlgorithm;
    const preferredHashAlgorithmVal = openpgp.config.preferredHashAlgorithm;
    const preferredCompressionAlgorithmVal = openpgp.config.preferredCompressionAlgorithm;
    const preferredAEADAlgorithmVal = openpgp.config.preferredAEADAlgorithm;
    openpgp.config.preferredSymmetricAlgorithm = openpgp.enums.symmetric.aes192;
    openpgp.config.preferredHashAlgorithm = openpgp.enums.hash.sha224;
    openpgp.config.preferredCompressionAlgorithm = openpgp.enums.compression.zlib;
    openpgp.config.preferredAEADAlgorithm = openpgp.enums.aead.eax;

    const testPref = function(key) {
      const selfSignature = openpgp.config.v6Keys ? key.directSignatures[0] : key.users[0].selfCertifications[0];
      // key flags
      const keyFlags = openpgp.enums.keyFlags;
      expect(selfSignature.keyFlags[0] & keyFlags.certifyKeys).to.equal(keyFlags.certifyKeys);
      expect(selfSignature.keyFlags[0] & keyFlags.signData).to.equal(keyFlags.signData);
      expect(key.subkeys[0].bindingSignatures[0].keyFlags[0] & keyFlags.encryptCommunication).to.equal(keyFlags.encryptCommunication);
      expect(key.subkeys[0].bindingSignatures[0].keyFlags[0] & keyFlags.encryptStorage).to.equal(keyFlags.encryptStorage);
      const sym = openpgp.enums.symmetric;
      expect(selfSignature.preferredSymmetricAlgorithms).to.eql([sym.aes192, sym.aes256, sym.aes128]);
      if (openpgp.config.aeadProtect) {
        const aead = openpgp.enums.aead;
        expect(selfSignature.preferredCipherSuites).to.eql([
          [sym.aes192, aead.eax],
          [sym.aes256, aead.eax],
          [sym.aes128, aead.eax],
          [sym.aes192, aead.gcm],
          [sym.aes256, aead.gcm],
          [sym.aes128, aead.gcm],
          [sym.aes192, aead.ocb],
          [sym.aes256, aead.ocb],
          [sym.aes128, aead.ocb]
        ]);
      }
      const hash = openpgp.enums.hash;
      expect(selfSignature.preferredHashAlgorithms).to.eql([hash.sha224, hash.sha512, hash.sha256, hash.sha3_512, hash.sha3_256]);
      const compr = openpgp.enums.compression;
      expect(selfSignature.preferredCompressionAlgorithms).to.eql([compr.zlib, compr.uncompressed, compr.zip]);

      let expectedFeatures = 0x01; // SEIPDv1
      if (openpgp.config.aeadProtect) {
        expectedFeatures |= 0x08; // SEIPDv2
      }
      expect(selfSignature.features).to.eql([expectedFeatures]);
    };
    const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: 'hello', format: 'object' };
    try {
      const { privateKey, publicKey } = await openpgp.generateKey(opt);
      testPref(privateKey);
      testPref(publicKey);
    } finally {
      openpgp.config.preferredSymmetricAlgorithm = preferredSymmetricAlgorithmVal;
      openpgp.config.preferredHashAlgorithm = preferredHashAlgorithmVal;
      openpgp.config.preferredCompressionAlgorithm = preferredCompressionAlgorithmVal;
      openpgp.config.preferredAEADAlgorithm = preferredAEADAlgorithmVal;
    }
  });

  it('Generated key is not unlocked by default', async function() {
    const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: '123', format: 'object' };
    const { privateKey: key } = await openpgp.generateKey(opt);
    return openpgp.encrypt({
      message: await openpgp.createMessage({ text: 'hello' }),
      encryptionKeys: key
    }).then(async armoredMessage => openpgp.decrypt({
      message: await openpgp.readMessage({ armoredMessage }),
      decryptionKeys: key
    })).catch(function(err) {
      expect(err.message).to.match(/Decryption key is not decrypted./);
    });
  });

  it('Generate key - single userID', function() {
    const userID = { name: 'test', email: 'a@b.com', comment: 'test comment' };
    const opt = { userIDs: userID, passphrase: '123', format: 'object' };
    return openpgp.generateKey(opt).then(function({ privateKey: key }) {
      expect(key.users.length).to.equal(1);
      expect(key.users[0].userID.userID).to.equal('test (test comment) <a@b.com>');
      expect(key.users[0].userID.name).to.equal(userID.name);
      expect(key.users[0].userID.email).to.equal(userID.email);
      expect(key.users[0].userID.comment).to.equal(userID.comment);
    });
  });

  it('Generate key - single userID (all empty)', function() {
    const userID = { name: '', email: '', comment: '' };
    const opt = { userIDs: userID, passphrase: '123', format: 'object' };
    return openpgp.generateKey(opt).then(function({ privateKey: key }) {
      expect(key.users.length).to.equal(1);
      expect(key.users[0].userID.userID).to.equal('');
      expect(key.users[0].userID.name).to.equal(userID.name);
      expect(key.users[0].userID.email).to.equal(userID.email);
      expect(key.users[0].userID.comment).to.equal(userID.comment);
    });
  });

  it('Generate key - single userID (empty email)', function() {
    const userID = { name: 'test', email: '', comment: 'test comment' };
    const opt = { userIDs: userID, passphrase: '123', format: 'object' };
    return openpgp.generateKey(opt).then(function({ privateKey: key }) {
      expect(key.users.length).to.equal(1);
      expect(key.users[0].userID.userID).to.equal('test (test comment)');
      expect(key.users[0].userID.name).to.equal(userID.name);
      expect(key.users[0].userID.email).to.equal(userID.email);
      expect(key.users[0].userID.comment).to.equal(userID.comment);
    });
  });

  it('Generate key - single userID (empty comment)', function() {
    const userID = { name: 'test', email: 'a@b.com', comment: '' };
    const opt = { userIDs: userID, passphrase: '123', format: 'object' };
    return openpgp.generateKey(opt).then(function({ privateKey: key }) {
      expect(key.users.length).to.equal(1);
      expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
      expect(key.users[0].userID.name).to.equal(userID.name);
      expect(key.users[0].userID.email).to.equal(userID.email);
      expect(key.users[0].userID.comment).to.equal(userID.comment);
    });
  });

  it('Generate key - single userID (special email format)', async function() {
    const userID = { name: 'test', email: 'test1@com.com09', comment: '' };
    const opt = { userIDs: userID };
    const { privateKey: armoredKey } = await openpgp.generateKey(opt);
    // test also serialisation and parsing
    const key = await openpgp.readKey({ armoredKey });
    expect(key.users.length).to.equal(1);
    expect(key.users[0].userID.userID).to.equal('test <test1@com.com09>');
    expect(key.users[0].userID.name).to.equal(userID.name);
    expect(key.users[0].userID.email).to.equal(userID.email);
    expect(key.users[0].userID.comment).to.equal(userID.comment);
  });

  it('Generate key - setting date to the past', function() {
    const past = new Date(0);
    const opt = {
      userIDs: { name: 'Test User', email: 'text@example.com' },
      passphrase: 'secret',
      date: past,
      format: 'object'
    };

    return openpgp.generateKey(opt).then(function({ privateKey }) {
      expect(privateKey).to.exist;
      expect(+privateKey.getCreationTime()).to.equal(+past);
      expect(+privateKey.subkeys[0].getCreationTime()).to.equal(+past);
      expect(+privateKey.subkeys[0].bindingSignatures[0].created).to.equal(+past);
    });
  });

  it('Generate key - setting date to the future', function() {
    const future = new Date(Math.ceil(Date.now() / 1000) * 1000 + 1000);
    const opt = {
      userIDs: { name: 'Test User', email: 'text@example.com' },
      passphrase: 'secret',
      date: future,
      format: 'object'
    };

    return openpgp.generateKey(opt).then(function({ privateKey }) {
      expect(privateKey).to.exist;
      expect(+privateKey.getCreationTime()).to.equal(+future);
      expect(+privateKey.subkeys[0].getCreationTime()).to.equal(+future);
      expect(+privateKey.subkeys[0].bindingSignatures[0].created).to.equal(+future);
    });
  });

  it('Generate key - multi userID', function() {
    const userID1 = { name: 'test', email: 'a@b.com' };
    const userID2 = { name: 'test', email: 'b@c.com' };
    const opt = { userIDs: [userID1, userID2], passphrase: '123', format: 'object' };
    return openpgp.generateKey(opt).then(function({ privateKey: key }) {
      expect(key.users.length).to.equal(2);
      expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
      expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
      expect(key.users[1].userID.userID).to.equal('test <b@c.com>');
      expect(key.users[1].selfCertifications[0].isPrimaryUserID).to.be.null;
    });
  });

  it('Generate key - default values', function() {
    const v6Key = openpgp.config.v6Keys;

    const userID = { name: 'test', email: 'a@b.com' };
    const opt = { userIDs: [userID], format: 'object' };
    return openpgp.generateKey(opt).then(function({ privateKey: key }) {
      expect(key.keyPacket.version).to.equal(v6Key ? 6 : 4);
      expect(key.isDecrypted()).to.be.true;
      expect(key.getAlgorithmInfo().algorithm).to.equal(v6Key ? 'ed25519' : 'eddsaLegacy');
      expect(key.users.length).to.equal(1);
      expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
      expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
      expect(key.subkeys).to.have.length(1);
      expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal(v6Key ? 'x25519' : 'ecdh');
    });
  });

  it('Generate key - two subkeys with default values', function() {
    const v6Key = openpgp.config.v6Keys;

    const userID = { name: 'test', email: 'a@b.com' };
    const opt = { userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{},{}] };
    return openpgp.generateKey(opt).then(function({ privateKey: key }) {
      expect(key.keyPacket.version).to.equal(v6Key ? 6 : 4);
      expect(key.users.length).to.equal(1);
      expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
      expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
      expect(key.subkeys).to.have.length(2);
      expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal(v6Key ? 'x25519' : 'ecdh');
      expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal(v6Key ? 'x25519' : 'ecdh');
    });
  });

  it('Generate RSA key - two subkeys with default values', async function() {
    const rsaBits = 1024;
    const minRSABits = openpgp.config.minRSABits;
    openpgp.config.minRSABits = rsaBits;

    const userID = { name: 'test', email: 'a@b.com' };
    const opt = { type: 'rsa', rsaBits, userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{},{}] };
    try {
      const { privateKey: key } = await openpgp.generateKey(opt);
      expect(key.users.length).to.equal(1);
      expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
      expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
      expect(key.subkeys).to.have.length(2);
      expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('rsaEncryptSign');
      expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal('rsaEncryptSign');
    } finally {
      openpgp.config.minRSABits = minRSABits;
    }
  });

  it('Generate Ed25519 key (new format) - default subkey', async function() {
    const userID = { name: 'test', email: 'a@b.com' };
    const opt = { type: 'curve25519', userIDs: [userID], passphrase: '123', format: 'object' };
    const { privateKey: key } = await openpgp.generateKey(opt);
    expect(key.users.length).to.equal(1);
    expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
    expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
    expect(key.getAlgorithmInfo().algorithm).to.equal('ed25519');
    expect(key.subkeys).to.have.length(1);
    expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('x25519');
  });

  it('Generate Ed25519 key (new format) - one signing subkey', async function() {
    const userID = { name: 'test', email: 'a@b.com' };
    const opt = { type: 'curve25519', userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{ sign: true }] };
    const { privateKey: key } = await openpgp.generateKey(opt);
    expect(key.users.length).to.equal(1);
    expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
    expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
    expect(key.getAlgorithmInfo().algorithm).to.equal('ed25519');
    expect(key.subkeys).to.have.length(1);
    expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ed25519');
  });

  it('Generate Ed448 key - default subkey', async function() {
    const userID = { name: 'test', email: 'a@b.com' };
    const opt = { type: 'curve448', userIDs: [userID], passphrase: '123', format: 'object' };
    const { privateKey: key } = await openpgp.generateKey(opt);
    expect(key.users.length).to.equal(1);
    expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
    expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
    expect(key.getAlgorithmInfo().algorithm).to.equal('ed448');
    expect(key.subkeys).to.have.length(1);
    expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('x448');
  });

  it('Generate Ed448 key - one signing subkey', async function() {
    const userID = { name: 'test', email: 'a@b.com' };
    const opt = { type: 'curve448', userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{ sign: true }] };
    const { privateKey: key } = await openpgp.generateKey(opt);
    expect(key.users.length).to.equal(1);
    expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
    expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
    expect(key.getAlgorithmInfo().algorithm).to.equal('ed448');
    expect(key.subkeys).to.have.length(1);
    expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ed448');
  });

  it('Generate key - one signing subkey', function() {
    const v6Key = openpgp.config.v6Keys;
    const userID = { name: 'test', email: 'a@b.com' };
    const opt = { userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{}, { sign: true }] };

    return openpgp.generateKey(opt).then(async function({ privateKey: key }) {
      expect(key.keyPacket.version).to.equal(v6Key ? 6 : 4);
      expect(key.users.length).to.equal(1);
      expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
      expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
      expect(key.subkeys).to.have.length(2);
      expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal(v6Key ? 'x25519' : 'ecdh');
      expect(await key.getEncryptionKey()).to.equal(key.subkeys[0]);
      expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal(v6Key ? 'ed25519' : 'eddsaLegacy');
      expect(await key.getSigningKey()).to.equal(key.subkeys[1]);
    });
  });

  it('Reformat key - one signing subkey', async function() {
    const v6Key = openpgp.config.v6Keys;
    const userID = { name: 'test', email: 'a@b.com' };
    const opt = { userIDs: [userID], format: 'object', subkeys:[{}, { sign: true }] };
    const { privateKey } = await openpgp.generateKey(opt);

    return openpgp.reformatKey({ privateKey, userIDs: [userID] }).then(async function({ privateKey: armoredKey }) {
      const key = await openpgp.readKey({ armoredKey });
      expect(key.keyPacket.version).to.equal(v6Key ? 6 : 4);
      expect(key.users.length).to.equal(1);
      expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
      expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
      expect(key.subkeys).to.have.length(2);
      expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal(v6Key ? 'x25519' : 'ecdh');
      expect(await key.getEncryptionKey()).to.equal(key.subkeys[0]);
      expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal(v6Key ? 'ed25519' : 'eddsaLegacy');
      expect(await key.getSigningKey()).to.equal(key.subkeys[1]);
    });
  });

  it('Generate key - override main RSA key options for subkey', async function() {
    const rsaBits = 1024;
    const minRSABits = openpgp.config.minRSABits;
    openpgp.config.minRSABits = rsaBits;

    const userID = { name: 'test', email: 'a@b.com' };
    const opt = { type: 'rsa', rsaBits, userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{ type: 'ecc', curve: 'nistP256' }] };
    try {
      const { privateKey: key } = await openpgp.generateKey(opt);
      expect(key.users.length).to.equal(1);
      expect(key.users[0].userID.userID).to.equal('test <a@b.com>');
      expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
      expect(key.getAlgorithmInfo().algorithm).to.equal('rsaEncryptSign');
      expect(key.getAlgorithmInfo().bits).to.equal(opt.rsaBits);
      expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh');
    } finally {
      openpgp.config.minRSABits = minRSABits;
    }
  });

  it('Generate key - ensure keyExpirationTime works', function() {
    const expect_delta = 365 * 24 * 60 * 60;
    const userID = { name: 'test', email: 'a@b.com' };
    const opt = { userIDs: userID, passphrase: '123', format: 'object', keyExpirationTime: expect_delta };
    return openpgp.generateKey(opt).then(async function({ privateKey: key }) {
      const expiration = await key.getExpirationTime();
      expect(expiration).to.exist;

      const actual_delta = (new Date(expiration) - new Date()) / 1000;
      expect(Math.abs(actual_delta - expect_delta)).to.be.below(60);

      const subkeyExpiration = await key.subkeys[0].getExpirationTime();
      expect(subkeyExpiration).to.exist;

      const actual_subkeyDelta = (new Date(subkeyExpiration) - new Date()) / 1000;
      expect(Math.abs(actual_subkeyDelta - expect_delta)).to.be.below(60);
    });
  });

  it('Sign and verify key - primary user', async function() {
    let publicKey = await openpgp.readKey({ armoredKey: pub_sig_test });
    const privateKey = await openpgp.decryptKey({
      privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
      passphrase: 'hello world'
    });

    const { minRSABits } = openpgp.config;
    openpgp.config.minRSABits = 1024;
    try {
      publicKey = await publicKey.signPrimaryUser([privateKey]);
      const signatures = await publicKey.verifyPrimaryUser([privateKey]);
      const publicSigningKey = await publicKey.getSigningKey();
      const privateSigningKey = await privateKey.getSigningKey();
      expect(signatures.length).to.equal(2);
      expect(signatures[0].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex());
      expect(signatures[0].valid).to.be.null;
      expect(signatures[1].keyID.toHex()).to.equal(privateSigningKey.getKeyID().toHex());
      expect(signatures[1].valid).to.be.true;
    } finally {
      openpgp.config.minRSABits = minRSABits;
    }
  });

  it('Sign key and verify with wrong key - primary user', async function() {
    let publicKey = await openpgp.readKey({ armoredKey: pub_sig_test });
    const wrongKey = await openpgp.readKey({ armoredKey: wrong_key });
    const privateKey = await openpgp.decryptKey({
      privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
      passphrase: 'hello world'
    });

    const { minRSABits } = openpgp.config;
    openpgp.config.minRSABits = 1024;
    try {
      publicKey = await publicKey.signPrimaryUser([privateKey]);
      const signatures = await publicKey.verifyPrimaryUser([wrongKey]);
      const publicSigningKey = await publicKey.getSigningKey();
      const privateSigningKey = await privateKey.getSigningKey();
      expect(signatures.length).to.equal(2);
      expect(signatures[0].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex());
      expect(signatures[0].valid).to.be.null;
      expect(signatures[1].keyID.toHex()).to.equal(privateSigningKey.getKeyID().toHex());
      expect(signatures[1].valid).to.be.null;
    } finally {
      openpgp.config.minRSABits = minRSABits;
    }
  });

  it('Sign and verify key - all users', async function() {
    let publicKey = await openpgp.readKey({ armoredKey: multi_uid_key });
    const privateKey = await openpgp.decryptKey({
      privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
      passphrase: 'hello world'
    });

    const { minRSABits } = openpgp.config;
    openpgp.config.minRSABits = 1024;
    try {
      publicKey = await publicKey.signAllUsers([privateKey]);
      const signatures = await publicKey.verifyAllUsers([privateKey]);
      const publicSigningKey = await publicKey.getSigningKey();
      const privateSigningKey = await privateKey.getSigningKey();
      expect(signatures.length).to.equal(4);
      expect(signatures[0].userID).to.equal(publicKey.users[0].userID.userID);
      expect(signatures[0].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex());
      expect(signatures[0].valid).to.be.null;
      expect(signatures[1].userID).to.equal(publicKey.users[0].userID.userID);
      expect(signatures[1].keyID.toHex()).to.equal(privateSigningKey.getKeyID().toHex());
      expect(signatures[1].valid).to.be.true;
      expect(signatures[2].userID).to.equal(publicKey.users[1].userID.userID);
      expect(signatures[2].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex());
      expect(signatures[2].valid).to.be.null;
      expect(signatures[3].userID).to.equal(publicKey.users[1].userID.userID);
      expect(signatures[3].keyID.toHex()).to.equal(privateSigningKey.getKeyID().toHex());
      expect(signatures[3].valid).to.be.true;
    } finally {
      openpgp.config.minRSABits = minRSABits;
    }
  });

  it('Sign key and verify with wrong key - all users', async function() {
    let publicKey = await openpgp.readKey({ armoredKey: multi_uid_key });
    const privateKey = await openpgp.decryptKey({
      privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
      passphrase: 'hello world'
    });
    const wrongKey = await openpgp.readKey({ armoredKey: wrong_key });

    const { minRSABits } = openpgp.config;
    openpgp.config.minRSABits = 1024;
    try {
      publicKey = await publicKey.signAllUsers([privateKey]);
      const signatures = await publicKey.verifyAllUsers([wrongKey]);
      const publicSigningKey = await publicKey.getSigningKey();
      const privateSigningKey = await privateKey.getSigningKey();
      expect(signatures.length).to.equal(4);
      expect(signatures[0].userID).to.equal(publicKey.users[0].userID.userID);
      expect(signatures[0].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex());
      expect(signatures[0].valid).to.be.null;
      expect(signatures[1].userID).to.equal(publicKey.users[0].userID.userID);
      expect(signatures[1].keyID.toHex()).to.equal(privateSigningKey.getKeyID().toHex());
      expect(signatures[1].valid).to.be.null;
      expect(signatures[2].userID).to.equal(publicKey.users[1].userID.userID);
      expect(signatures[2].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex());
      expect(signatures[2].valid).to.be.null;
      expect(signatures[3].userID).to.equal(publicKey.users[1].userID.userID);
      expect(signatures[3].keyID.toHex()).to.equal(privateSigningKey.getKeyID().toHex());
      expect(signatures[3].valid).to.be.null;
    } finally {
      openpgp.config.minRSABits = minRSABits;
    }
  });

  it('Sign and verify a key with user attribute - all users', async function () {
    let publicKey = await openpgp.readKey({ armoredKey: keyWithImageData });
    const privateKey = await openpgp.decryptKey({
      privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
      passphrase: 'hello world'
    });

    const { minRSABits } = openpgp.config;
    openpgp.config.minRSABits = 1024;
    try {
      publicKey = await publicKey.signAllUsers([privateKey]);
      const signatures = await publicKey.verifyAllUsers([privateKey]);
      const publicSigningKey = await publicKey.getSigningKey();
      const privateSigningKey = await privateKey.getSigningKey();
      expect(signatures.length).to.equal(4);
      expect(signatures[0].userID).to.equal(publicKey.users[0].userID.userID);
      expect(signatures[0].userAttribute).to.be.null;
      expect(signatures[0].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex());
      expect(signatures[0].valid).to.be.null;
      expect(signatures[1].userID).to.equal(publicKey.users[0].userID.userID);
      expect(signatures[1].userAttribute).to.be.null;
      expect(signatures[1].keyID.toHex()).to.equal(privateSigningKey.getKeyID().toHex());
      expect(signatures[1].valid).to.be.true;
      expect(signatures[2].userID).to.be.null;
      expect(signatures[2].userAttribute.attributes[0]).to.be.not.empty;
      expect(signatures[2].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex());
      expect(signatures[2].valid).to.be.null;
      expect(signatures[3].userID).to.be.null;
      expect(signatures[3].userAttribute.attributes[0]).to.be.not.empty;
      expect(signatures[3].keyID.toHex()).to.equal(privateSigningKey.getKeyID().toHex());
      expect(signatures[3].valid).to.be.true;
    } finally {
      openpgp.config.minRSABits = minRSABits;
    }
  });

  it('Sign and verify a key with user attribute using wrong key - all users', async function () {
    let publicKey = await openpgp.readKey({ armoredKey: keyWithImageData });
    const privateKey = await openpgp.decryptKey({
      privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
      passphrase: 'hello world'
    });
    const wrongKey = await openpgp.readKey({ armoredKey: wrong_key });

    const { minRSABits } = openpgp.config;
    openpgp.config.minRSABits = 1024;
    try {
      publicKey = await publicKey.signAllUsers([privateKey]);
      const signatures = await publicKey.verifyAllUsers([wrongKey]);
      const publicSigningKey = await publicKey.getSigningKey();
      const privateSigningKey = await privateKey.getSigningKey();
      expect(signatures.length).to.equal(4);
      expect(signatures[0].userID).to.equal(publicKey.users[0].userID.userID);
      expect(signatures[0].userAttribute).to.be.null;
      expect(signatures[0].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex());
      expect(signatures[0].valid).to.be.null;
      expect(signatures[1].userID).to.equal(publicKey.users[0].userID.userID);
      expect(signatures[1].userAttribute).to.be.null;
      expect(signatures[1].keyID.toHex()).to.equal(privateSigningKey.getKeyID().toHex());
      expect(signatures[1].valid).to.be.null;
      expect(signatures[2].userID).to.be.null;
      expect(signatures[2].userAttribute.attributes[0]).to.be.not.empty;
      expect(signatures[2].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex());
      expect(signatures[2].valid).to.be.null;
      expect(signatures[3].userID).to.be.null;
      expect(signatures[3].userAttribute.attributes[0]).to.be.not.empty;
      expect(signatures[3].keyID.toHex()).to.equal(privateSigningKey.getKeyID().toHex());
      expect(signatures[3].valid).to.be.null;
    } finally {
      openpgp.config.minRSABits = minRSABits;
    }
  });

  it('Reformat and encrypt key with no subkey', async function() {
    const userID = { name: 'test', email: 'a@b.com' };
    const key = await openpgp.readKey({ armoredKey: key_without_subkey });
    const opt = { privateKey: key, userIDs: [userID], passphrase: 'test', format: 'object' };
    return openpgp.reformatKey(opt).then(function({ privateKey: newKey }) {
      expect(newKey.users.length).to.equal(1);
      expect(newKey.users[0].userID.userID).to.equal('test <a@b.com>');
      expect(newKey.isDecrypted()).to.be.false;
    });
  });

  it('Reformat key with one subkey', async function() {
    const original = await openpgp.readKey({ armoredKey: priv_key_rsa });
    const privateKey = await openpgp.decryptKey({ privateKey: original, passphrase: 'hello world' });

    const userID = { name: 'test', email: 'b@c.com' };
    const before = new Date(0);
    expect(+privateKey.getCreationTime()).to.not.equal(+before);
    expect(+privateKey.subkeys[0].getCreationTime()).to.not.equal(+before);
    expect(+privateKey.subkeys[0].bindingSignatures[0].created).to.not.equal(+before);
    const opt = { privateKey, userIDs: userID, date: before, format: 'object' };
    return openpgp.reformatKey(opt).then(function({ privateKey: refKey }) {
      expect(refKey.users.length).to.equal(1);
      expect(refKey.users[0].userID.userID).to.equal('test <b@c.com>');
      expect(+refKey.subkeys[0].bindingSignatures[0].created).to.equal(+before);
    });
  });

  it('Reformat key with no subkey', async function() {
    const userID = { name: 'test', email: 'a@b.com' };
    const key = await openpgp.readKey({ armoredKey: key_without_subkey });
    const opt = { privateKey: key, userIDs: [userID], format: 'object' };
    return openpgp.reformatKey(opt).then(async function({ privateKey: newKey, publicKey: newKeyPublic }) {
      expect(newKey.users.length).to.equal(1);
      expect(newKey.users[0].userID.userID).to.equal('test <a@b.com>');
      expect(newKey.isDecrypted()).to.be.true;
      return openpgp.sign({ message: await openpgp.createCleartextMessage({ text: 'hello' }), signingKeys: newKey }).then(async function(signed) {
        return openpgp.verify(
          { message: await openpgp.readCleartextMessage({ cleartextMessage: signed }), verificationKeys: newKeyPublic }
        ).then(async function(verified) {
          expect(await verified.signatures[0].verified).to.be.true;
          const newSigningKey = await newKey.getSigningKey();
          expect(verified.signatures[0].keyID.toHex()).to.equal(newSigningKey.getKeyID().toHex());
          expect((await verified.signatures[0].signature).packets.length).to.equal(1);
        });
      });
    });
  });

  it('Reformat and encrypt key', async function() {
    const original = await openpgp.readKey({ armoredKey: priv_key_rsa });
    const privateKey = await openpgp.decryptKey({ privateKey: original, passphrase: 'hello world' });

    const userID1 = { name: 'test2', email: 'b@c.com' };
    const userID2 = { name: 'test3', email: 'c@d.com' };
    const passphrase = '123';
    const reformatOpt = { privateKey, userIDs: [userID1, userID2], passphrase, format: 'object' };
    return openpgp.reformatKey(reformatOpt).then(async ({ privateKey: refKey }) => {
      expect(refKey.users.length).to.equal(2);
      expect(refKey.users[0].userID.userID).to.equal('test2 <b@c.com>');
      expect(refKey.isDecrypted()).to.be.false;
      const decryptedKey = await openpgp.decryptKey({ privateKey: refKey, passphrase });
      expect(decryptedKey.isDecrypted()).to.be.true;
    });
  });

  it('Sign and encrypt with reformatted key', async function() {
    const userID1 = { name: 'test1', email: 'a@b.com' };
    const userID2 = { name: 'test2', email: 'b@c.com' };
    const { privateKey } = await openpgp.generateKey({ userIDs: userID1, format: 'object' });

    const opt2 = { privateKey, userIDs: userID2, format: 'object' };
    return openpgp.reformatKey(opt2).then(async function({ privateKey: newKey, publicKey: newKeyPublic }) {
      const encrypted = await openpgp.encrypt({
        message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: newKey.toPublic(), signingKeys: newKey, config: { minRSABits: 1024 }
      });
      const decrypted = await openpgp.decrypt({
        message: await openpgp.readMessage({ armoredMessage: encrypted }), decryptionKeys: newKey, verificationKeys: newKeyPublic, config: { minRSABits: 1024 }
      });
      expect(decrypted.data).to.equal('hello');
      expect(await decrypted.signatures[0].verified).to.be.true;
    });
  });

  it('Reject with user-friendly error when reformatting encrypted key', async function() {
    const privateKey = await openpgp.readKey({ armoredKey: priv_key_rsa });

    await expect(
      openpgp.reformatKey({ privateKey, userIDs: { name: 'test2', email: 'a@b.com' }, passphrase: '1234' })
    ).to.be.rejectedWith('Error reformatting keypair: Key is not decrypted');
  });

  it('Revoke generated key with revocation certificate', async function() {
    const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: '1234', format: 'object' };
    const { publicKey, revocationCertificate } = await openpgp.generateKey(opt);
    return openpgp.revokeKey({ key: publicKey, revocationCertificate, format: 'object' }).then(async function({ publicKey: revKey }) {
      expect(revKey.revocationSignatures[0].reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.noReason);
      expect(revKey.revocationSignatures[0].reasonForRevocationString).to.equal('');
      await expect(revKey.verifyPrimaryKey()).to.be.rejectedWith('Primary key is revoked');
    });
  });

  it('Revoke generated key with private key', async function() {
    const opt = { userIDs: { name: 'test', email: 'a@b.com' }, format: 'object' };
    const { privateKey: key } = await openpgp.generateKey(opt);
    return openpgp.revokeKey({ key, reasonForRevocation: { string: 'Testing key revocation' }, format: 'object' }).then(async function({ publicKey: revKey }) {
      expect(revKey.revocationSignatures[0].reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.noReason);
      expect(revKey.revocationSignatures[0].reasonForRevocationString).to.equal('Testing key revocation');
      await expect(revKey.verifyPrimaryKey()).to.be.rejectedWith('Primary key is revoked');
    });
  });

  it('Revoke reformatted key with revocation certificate', async function() {
    const original = await openpgp.readKey({ armoredKey: priv_key_rsa });
    const privateKey = await openpgp.decryptKey({ privateKey: original, passphrase: 'hello world' });

    const opt = { privateKey, userIDs: { name: 'test', email: 'a@b.com' }, format: 'object' };
    const { publicKey: refKey, revocationCertificate } = await openpgp.reformatKey(opt);
    return openpgp.revokeKey({ key: refKey, revocationCertificate, format: 'object' }).then(async function({ publicKey: revKey }) {
      expect(revKey.revocationSignatures[0].reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.noReason);
      expect(revKey.revocationSignatures[0].reasonForRevocationString).to.equal('');
      await expect(revKey.verifyPrimaryKey()).to.be.rejectedWith('Primary key is revoked');
      await expect(privateKey.verifyPrimaryKey()).to.be.fulfilled;
    });
  });
}

export default () => describe('Key', function() {
  let v6KeysVal;
  let aeadProtectVal;

  tryTests('V4', versionSpecificTests, {
    if: true,
    beforeEach: function() {
      v6KeysVal = openpgp.config.v6Keys;
      openpgp.config.v6Keys = false;
    },
    afterEach: function() {
      openpgp.config.v6Keys = v6KeysVal;
    }
  });

  tryTests('V6', versionSpecificTests, {
    if: true,
    beforeEach: function() {
      v6KeysVal = openpgp.config.v6Keys;
      aeadProtectVal = openpgp.config.aeadProtect;
      openpgp.config.v6Keys = true;
      openpgp.config.aeadProtect = true;
    },
    afterEach: function() {
      openpgp.config.v6Keys = v6KeysVal;
      openpgp.config.aeadProtect = aeadProtectVal;
    }
  });

  it('Parsing armored text with RSA key and ECC subkey', async function() {
    const pubKeys = await openpgp.readKeys({ armoredKeys: rsa_ecc_pub });
    expect(pubKeys).to.exist;
    expect(pubKeys).to.have.length(1);
    expect(pubKeys[0].getKeyID().toHex()).to.equal('b8e4105cc9dedc77');
  });

  it('Parsing armored text with two keys', async function() {
    const pubKeys = await openpgp.readKeys({ armoredKeys: twoKeys });
    expect(pubKeys).to.exist;
    expect(pubKeys).to.have.length(2);
    expect(pubKeys[0].getKeyID().toHex()).to.equal('4a63613a4d6e4094');
    expect(pubKeys[1].getKeyID().toHex()).to.equal('dbf223e870534df4');
  });

  it('Parsing armored key with an authorized revocation key in a User ID self-signature', async function() {
    const pubKey = await openpgp.readKey({ armoredKey: key_with_authorized_revocation_key });
    await expect(pubKey.getPrimaryUser()).to.be.rejectedWith('This key is intended to be revoked with an authorized key, which OpenPGP.js does not support.');
  });

  it('Parsing armored key with an authorized revocation key in a direct-key signature', async function() {
    const pubKey = await openpgp.readKey({ armoredKey: key_with_authorized_revocation_key_in_separate_sig });
    const primaryUser = await pubKey.getPrimaryUser();
    expect(primaryUser).to.exist;
  });

  it('Parsing and serialization of encrypted key with unknown S2K type (unparseableKeyMaterial)', async function() {
    const key = await openpgp.readKey({ armoredKey: encryptedKeyUnknownS2K });
    expect(key.isPrivate()).to.equal(true);
    expect(key.isDecrypted()).to.equal(false);
    expect(key.getSubkeys()).to.have.length(1);
    expect(key.keyPacket.isMissingSecretKeyMaterial()).to.equal(true);

    const expectedSerializedKey = await openpgp.unarmor(encryptedKeyUnknownS2K);
    expect(key.write()).to.deep.equal(expectedSerializedKey.data);
  });

  it('Parses V5 sample key', async function() {
    // sec   ed25519 2019-03-20 [SC]
    //       19347BC9872464025F99DF3EC2E0000ED9884892E1F7B3EA4C94009159569B54
    // uid                      emma.goldman@example.net
    // ssb   cv25519 2019-03-20 [E]
    //       E4557C2B02FFBF4B04F87401EC336AF7133D0F85BE7FD09BAEFD9CAEB8C93965
    const key = await openpgp.readKey({ armoredKey: v5_sample_key, config: { enableParsingV5Entities: true } });
    expect(key.keyPacket.getFingerprint()).to.equal('19347bc9872464025f99df3ec2e0000ed9884892e1f7b3ea4c94009159569b54');
    expect(key.subkeys[0].getFingerprint()).to.equal('e4557c2b02ffbf4b04f87401ec336af7133d0f85be7fd09baefd9caeb8c93965');
    await key.verifyPrimaryKey();
  });

  it('Parsing V5 public key packet', async function() {
    // Manually modified from https://gitlab.com/openpgp-wg/rfc4880bis/blob/00b2092/back.mkd#sample-eddsa-key
    const packetBytes = util.hexToUint8Array(`
      98 37 05 53 f3 5f 0b 16  00 00 00 2d  09 2b 06 01 04 01 da 47
      0f 01 01 07 40 3f 09 89  94 bd d9 16 ed 40 53 19
      79 34 e4 a8 7c 80 73 3a  12 80 d6 2f 80 10 99 2e
      43 ee 3b 24 06
    `.replace(/\s+/g, ''));

    const packetlist = await openpgp.PacketList.fromBinary(packetBytes, util.constructAllowedPackets([openpgp.PublicKeyPacket]), openpgp.config);
    const key = packetlist[0];
    expect(key).to.exist;
  });

  it('Parsing, decrypting, encrypting and serializing V5 key (AEAD-encrypted)', async function() {
    const armoredKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----

xYwFZC7tvxYAAAAtCSsGAQQB2kcPAQEHQP/d1oBAqCKZYxb6k8foyX2Aa/VK
dHFymZPGvHRk1ncs/R0JAQMIrDnS3Bany9EAF6dwQSfPSdObc4ROYIMAnwAA
ADKV1OhGzwANnapimvODI6fK5F7/V0GxETY9WmnipnBzr4Fe9GZw4QD4Q4hd
IJMawjUBrs0MdjVAYWVhZC50ZXN0wpIFEBYKAEQFgmQu7b8ECwkHCAMVCAoE
FgACAQIZAQKbAwIeByKhBQ/Y89PNwfdXUdI/td5Q9rNrYP9mb7Dg6k/3nxTg
ugQ5AyIBAgAAf0kBAJv0OQvd4u8R0f3HAsmQeqMnwNA4or75BOn/ieApNZUt
AP9kQVmYEk4+MV57Us15l2kQEslLDr3qiH5+VCICdEprB8eRBWQu7b8SAAAA
MgorBgEEAZdVAQUBAQdA4IgEkfze3eNKRz6DgzGSJxw/CV/5Rp5u4Imn47h7
pyADAQgH/R0JAQMIwayD3R4E0ugAyszSmOIpaLJ40YGBp5uU7wAAADKmSv4W
tio7GfZCVl8eJ7xX3J1b0iMvEm876tUeHANQlYYCWz+2ahmPVe79zzZA9OhN
FcJ6BRgWCAAsBYJkLu2/ApsMIqEFD9jz083B91dR0j+13lD2s2tg/2ZvsODq
T/efFOC6BDkAAHcjAPwIPNHnR9bKmkVop6cE05dCIpZ/W8zXDGnjKYrrC4Hb
4gEAmISD1GRkNOmCV8aHwN5svO6HuwXR4cR3o3l7HlYeag8=
=wpkQ
-----END PGP PRIVATE KEY BLOCK-----`;
    const passphrase = 'password';
    const encryptedKey = await openpgp.readKey({ armoredKey, config: { enableParsingV5Entities: true } });
    const decryptedKey = await openpgp.decryptKey({
      privateKey: encryptedKey,
      passphrase
    });
    const reecryptedKey = await openpgp.encryptKey({
      privateKey: decryptedKey,
      passphrase,
      config: { aeadProtect: true }
    });
    expect(reecryptedKey.keyPacket.s2kUsage).to.equal(253);
    const redecryptedKey = await openpgp.decryptKey({
      privateKey: reecryptedKey,
      passphrase
    });
    expect(redecryptedKey.write()).to.deep.equal(decryptedKey.write());
  });

  it('Parsing, decrypting, encrypting and serializing V4 key (AEAD-encrypted, deprecated/legacy format from RFC4880bis)', async function() {
    // v4 key from OpenPGP.js v5, generated with config.aeadProtect flag (https://www.ietf.org/archive/id/draft-ietf-openpgp-rfc4880bis-10.html#section-5.5.3-3.5)
    const armoredKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----

xYMEZPXfehYJKwYBBAHaRw8BAQdAw/62MUaSzRSY5gR18DOlfeo/m8eKUkbr
ZSRqS4wtss39CQEDCGHd70SYYYPkAAALGg1YptTjEuIk4wiBreDE9U/urf3J
6Z8fP3oy+plzBRKs+8k+kzXY/643Ayesfy3qXA4zM6fqNrrlS6AqT8wDys0A
wpAEEBYKAEIFgmT133oECwkHCAmQB4Z/qOo0isgDFQgKBBYAAgECGQECmwMC
HgMWIQQm7YhFQvi0bx7ixrQHhn+o6jSKyAMiAQIAADQZAP9kECruRBva4izE
9ZET1iQ6i1HiisUKrO6miHfjsxDycgD9EXvtbpi1AORIrYO/pPpGUHpUt25n
JM+rgWhJwOHw1g3HiARk9d96EgorBgEEAZdVAQUBAQdAiVNiLZRC9wZG9/ef
V9eu8VKEoHqAFjci3Lu2N+8hQQoDAQgH/QkBAwh+kYDhbTGARwBZRY0lR39D
EriFZ1N5PKW1TAdxTMNecP3sOyUWRutHQgRrxuF0512fCnelgr2a3of5bQHC
0XWFfbac2d91VEP2mqrCeAQYFggAKgWCZPXfegmQB4Z/qOo0isgCmwwWIQQm
7YhFQvi0bx7ixrQHhn+o6jSKyAAAkN4A/31Hm3vy7FHFGJh+VYdqmeESo7mr
18jzxSbxd71FGTw7AQDqfERTB7zZzk1EqNSAqfrg3hbI7+4XXgHz6qnA3vFm
Cg==
=mTGB
-----END PGP PRIVATE KEY BLOCK-----`;
    const binaryKey = (await openpgp.unarmor(armoredKey)).data;
    const passphrase = 'passphrase';
    const encryptedKey = await openpgp.readKey({ armoredKey, config: { parseAEADEncryptedV4KeysAsLegacy: true } });
    expect(encryptedKey.keyPacket.isLegacyAEAD).to.be.true;
    expect(encryptedKey.keyPacket.usedModernAEAD).to.be.false; // legacy AEAD does not guarantee integrity of public key material
    expect(encryptedKey.write()).to.deep.equal(binaryKey);

    const decryptedKey = await openpgp.decryptKey({
      privateKey: encryptedKey,
      passphrase
    });
    const reecryptedKey = await openpgp.encryptKey({
      privateKey: decryptedKey,
      passphrase,
      config: { aeadProtect: true }
    });
    expect(reecryptedKey.keyPacket.s2kUsage).to.equal(253);
    expect(reecryptedKey.keyPacket.isLegacyAEAD).to.be.false;
    const redecryptedKey = await openpgp.decryptKey({
      privateKey: reecryptedKey,
      passphrase
    });
    expect(redecryptedKey.write()).to.deep.equal(decryptedKey.write());
  });

  it('Parsing, decrypting, encrypting and serializing V5 key (AEAD-encrypted, deprecated/legacy format from RFC4880bis)', async function() {
    // v5 key from OpenPGP.js v5, generated with config.aeadProtect flag (https://www.ietf.org/archive/id/draft-ietf-openpgp-rfc4880bis-10.html#section-5.5.3-3.5)
    const armoredKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----

xYwFZoaoyxYAAAAtCSsGAQQB2kcPAQEHQECiSN62X9PnTUoE9cx6aRxqh2aR
piHEjy2dtbhOsC7X/R0JAQMI3R4vBY0cUVnglteNXGCjgMgSTO3VeB70tgAA
ADIUlEIeqChwz1NRWl0WafC7vLrhIwgzW4dfRLqWU/tcDxhQji8oOdMihMVH
gOT1M/58zs0EVGVzdMKSBRAWCgBEBYJmhqjLBAsJBwgDFQgKBBYAAgECGQEC
mwMCHgcioQVBp/l8xtMGAhUT99DQhSQ8spB7ILxEALjWUfi5ODEQZgMiAQIA
ABJ7AQDbdXScaIjOUmKjsX1pTeDPfIPEWJSBY5n4e9tKMoFLuAD+ISyssmch
WjtxzfvElCc4/QL7P4yv7VBCHgVMfdBIggPHkQVmhqjLEgAAADIKKwYBBAGX
VQEFAQEHQL5K5HBcf0/GTcajPc3xeNNQQhJfT0TsmcorbEWV73FZAwEIB/0d
CQEDCJ2Wqcffz5cT4LmtIq4KlZUR8vlQrKcWF5MAAAAyiqtRwe6bSZ94e8Yt
1O6D4oH37UnCkKEuDQJb3G4SvHw4lJdlehfRFxndhHTuTVNQW9zCegUYFgoA
LAWCZoaoywKbDCKhBUGn+XzG0wYCFRP30NCFJDyykHsgvEQAuNZR+Lk4MRBm
AADOyAEA0VMzgtpSnXOfPNvVjOOW3yW/DnHSnOWjLmUujTLYXf0A/0nHjVMI
yrHaO8+1bQew7SIS9kYr1sh/z7LKooqYHBwH
=Woga
-----END PGP PRIVATE KEY BLOCK-----`;
    const binaryKey = (await openpgp.unarmor(armoredKey)).data;
    const passphrase = 'passphrase';
    const encryptedKey = await openpgp.readKey({ armoredKey, config: { enableParsingV5Entities: true } });
    expect(encryptedKey.keyPacket.isLegacyAEAD).to.be.true;
    expect(encryptedKey.keyPacket.usedModernAEAD).to.be.false; // legacy AEAD does not guarantee integrity of public key material
    expect(encryptedKey.write()).to.deep.equal(binaryKey);

    const decryptedKey = await openpgp.decryptKey({
      privateKey: encryptedKey,
      passphrase
    });
    const reecryptedKey = await openpgp.encryptKey({
      privateKey: decryptedKey,
      passphrase,
      config: { aeadProtect: true }
    });
    expect(reecryptedKey.keyPacket.s2kUsage).to.equal(253);
    expect(reecryptedKey.keyPacket.isLegacyAEAD).to.be.true;
    const redecryptedKey = await openpgp.decryptKey({
      privateKey: reecryptedKey,
      passphrase
    });
    expect(redecryptedKey.write()).to.deep.equal(decryptedKey.write());
  });

  it('Parsing, decrypting, encrypting and serializing V4 key (AEAD-encrypted)', async function() {
    // key from gopenpgp
    const armoredKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----

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
oZIvKIVq9Vqf8XJVjMDbRMNTmh3a5A==
-----END PGP PRIVATE KEY BLOCK-----`;
    const passphrase = 'password';
    const encryptedKey = await openpgp.readKey({ armoredKey });
    const decryptedKey = await openpgp.decryptKey({
      privateKey: encryptedKey,
      passphrase
    });
    const reecryptedKey = await openpgp.encryptKey({
      privateKey: decryptedKey,
      passphrase,
      config: { aeadProtect: true }
    });
    expect(reecryptedKey.keyPacket.s2kUsage).to.equal(253);
    const redecryptedKey = await openpgp.decryptKey({
      privateKey: reecryptedKey,
      passphrase
    });
    expect(redecryptedKey.write()).to.deep.equal(decryptedKey.write());
  });

  it('Parsing, decrypting, encrypting and serializing V6 key (AEAD-encrypted)', async function() {
    // official test vector from https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#appendix-A.5
    const armoredKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----

xYIGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laP9JgkC
FARdb9ccngltHraRe25uHuyuAQQVtKipJ0+r5jL4dacGWSAheCWPpITYiyfyIOPS
3gIDyg8f7strd1OB4+LZsUhcIjOMpVHgmiY/IutJkulneoBYwrEGHxsKAAAAQgWC
Y4d/4wMLCQcFFQoOCAwCFgACmwMCHgkiIQbLGGxPBgmml+TVLfpscisMHx4nwYpW
cI9lJewnutmsyQUnCQIHAgAAAACtKCAQPi19In7A5tfORHHbNr/JcIMlNpAnFJin
7wV2wH+q4UWFs7kDsBJ+xP2i8CMEWi7Ha8tPlXGpZR4UruETeh1mhELIj5UeM8T/
0z+5oX1RHu11j8bZzFDLX9eTsgOdWATHggZjh3/jGQAAACCGkySDZ/nlAV25Ivj0
gJXdp4SYfy1ZhbEvutFsr15ENf0mCQIUBA5hhGgp2oaavg6mFUXcFMwBBBUuE8qf
9Ock+xwusd+GAglBr5LVyr/lup3xxQvHXFSjjA2haXfoN6xUGRdDEHI6+uevKjVR
v5oAxgu7eJpaXNjCmwYYGwoAAAAsBYJjh3/jApsMIiEGyxhsTwYJppfk1S36bHIr
DB8eJ8GKVnCPZSXsJ7rZrMkAAAAABAEgpukYbZ1ZNfyP5WMUzbUnSGpaUSD5t2Ki
Nacp8DkBClZRa2c3AMQzSDXa9jGhYzxjzVb5scHDzTkjyRZWRdTq8U6L4da+/+Kt
ruh8m7Xo2ehSSFyWRSuTSZe5tm/KXgYG
-----END PGP PRIVATE KEY BLOCK-----`;
    const passphrase = 'correct horse battery staple';
    const encryptedKey = await openpgp.readKey({ armoredKey });

    // avoid argon2's expensive computation
    const stubArgon2PrimaryKey = sinon.stub(encryptedKey.keyPacket.s2k, 'produceKey').returns(
      util.hexToUint8Array('832bd2662a5c2b251ee3fc82aec349a766ca539015880133002e5a21960b3bcf'));
    const stubArgon2Subkey = sinon.stub(encryptedKey.subkeys[0].keyPacket.s2k, 'produceKey').returns(
      util.hexToUint8Array('f74a6ce873a089ef13a3da9ac059777bb22340d15eaa6c9dc0f8ef09035c67cd'));

    try {
      const decryptedKey = await openpgp.decryptKey({
        privateKey: encryptedKey,
        passphrase
      });

      const reecryptedKey = await openpgp.encryptKey({
        privateKey: decryptedKey,
        passphrase,
        config: { aeadProtect: true }
      });
      expect(reecryptedKey.keyPacket.s2kUsage).to.equal(253);
      const redecryptedKey = await openpgp.decryptKey({
        privateKey: reecryptedKey,
        passphrase
      });
      expect(redecryptedKey.write()).to.deep.equal(decryptedKey.write());
    } finally {
      stubArgon2PrimaryKey.restore();
      stubArgon2Subkey.restore();
    }
  });

  it('Parsing EdDSALegacy key with unsupported OID (Curve448Legacy)', async function() {
    // Key with unknown OID (corresponding to curve448) which is not supported for EdDSALegacy
    const armoredEdDSALegacyCurve448Key = `-----BEGIN PGP PRIVATE KEY BLOCK-----

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
QgqsfguR1PqPuJxpXV4bSr6CGAAAAA==
=MSvh
-----END PGP PRIVATE KEY BLOCK-----
`;
    await expect(openpgp.readKey({ armoredKey: armoredEdDSALegacyCurve448Key })).to.be.rejectedWith(/No key packet found/);

    await expect(openpgp.readKey({
      armoredKey: armoredEdDSALegacyCurve448Key,
      config: { ignoreUnsupportedPackets: false }
    })).to.be.rejectedWith(/Unknown curve OID/);
  });

  it('Parsing ECDH key with unknown kdf param version', async function() {
    // subkey with unknown kdfParam version 255. Parsing should not fail, the subkey should simply dropped
    const key = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----

xVgEZAdtGBYJKwYBBAHaRw8BAQdAcNgHyRGEaqGmzEqEwCobfUkyrJnY8faBvsf9
R2c5ZzYAAP9bFL4nPBdo04ei0C2IAh5RXOpmuejGC3GAIn/UmL5cYQ+XzRtjaGFy
bGVzIDxjaGFybGVzQHByb3Rvbi5tZT7CigQTFggAPAUCZAdtGAmQFXJtmBzDhdcW
IQRl2gNflypl1XjRUV8Vcm2YHMOF1wIbAwIeAQIZAQILBwIVCAIWAAIiAQAAJKYA
/2qY16Ozyo5erNz51UrKViEoWbEpwY3XaFVNzrw+b54YAQC7zXkf/t5ieylvjmA/
LJz3/qgH5GxZRYAH9NTpWyW1AsdxBGQHbRgSCisGAQQBl1UBBQEBB0CxmxoJsHTW
TiETWh47ot+kwNA1hCk1IYB9WwKxkXYyIBf/CgmKXzV1ODP/mRmtiBYVV+VQk5MF
EAAA/1NW8D8nMc2ky140sPhQrwkeR7rVLKP2fe5n4BEtAnVQEB3CeAQYFggAKgUC
ZAdtGAmQFXJtmBzDhdcWIQRl2gNflypl1XjRUV8Vcm2YHMOF1wIbUAAAl/8A/iIS
zWBsBR8VnoOVfEE+VQk6YAi7cTSjcMjfsIez9FYtAQDKo9aCMhUohYyqvhZjn8aS
3t9mIZPc+zRJtCHzQYmhDg==
=lESj
-----END PGP PRIVATE KEY BLOCK-----` });

    expect(key.subkeys).to.have.length(0);

    await expect(openpgp.readKey({
      armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----

xVgEZAdtGBYJKwYBBAHaRw8BAQdAcNgHyRGEaqGmzEqEwCobfUkyrJnY8faBvsf9
R2c5ZzYAAP9bFL4nPBdo04ei0C2IAh5RXOpmuejGC3GAIn/UmL5cYQ+XzRtjaGFy
bGVzIDxjaGFybGVzQHByb3Rvbi5tZT7CigQTFggAPAUCZAdtGAmQFXJtmBzDhdcW
IQRl2gNflypl1XjRUV8Vcm2YHMOF1wIbAwIeAQIZAQILBwIVCAIWAAIiAQAAJKYA
/2qY16Ozyo5erNz51UrKViEoWbEpwY3XaFVNzrw+b54YAQC7zXkf/t5ieylvjmA/
LJz3/qgH5GxZRYAH9NTpWyW1AsdxBGQHbRgSCisGAQQBl1UBBQEBB0CxmxoJsHTW
TiETWh47ot+kwNA1hCk1IYB9WwKxkXYyIBf/CgmKXzV1ODP/mRmtiBYVV+VQk5MF
EAAA/1NW8D8nMc2ky140sPhQrwkeR7rVLKP2fe5n4BEtAnVQEB3CeAQYFggAKgUC
ZAdtGAmQFXJtmBzDhdcWIQRl2gNflypl1XjRUV8Vcm2YHMOF1wIbUAAAl/8A/iIS
zWBsBR8VnoOVfEE+VQk6YAi7cTSjcMjfsIez9FYtAQDKo9aCMhUohYyqvhZjn8aS
3t9mIZPc+zRJtCHzQYmhDg==
=lESj
-----END PGP PRIVATE KEY BLOCK-----`,
      config: { ignoreUnsupportedPackets: false }
    })).to.be.rejectedWith(/Cannot read KDFParams/);
  });

  it('Parsing V4 key using new curve25519 format', async function() {
    const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----

xUkEZB3qzRto01j2k2pwN5ux9w70stPinAdXULLr20CRW7U7h2GSeACch0M+
qzQg8yjFQ8VBvu3uwgKH9senoHmj72lLSCLTmhFKzQR0ZXN0wogEEBsIAD4F
gmQd6s0ECwkHCAmQIf45+TuC+xMDFQgKBBYAAgECGQECmwMCHgEWIQSWEzMi
jJUHvyIbVKIh/jn5O4L7EwAAUhaHNlgudvxARdPPETUzVgjuWi+YIz8w1xIb
lHQMvIrbe2sGCQIethpWofd0x7DHuv/ciHg+EoxJ/Td6h4pWtIoKx0kEZB3q
zRm4CyA7quliq7yx08AoOqHTuuCgvpkSdEhpp3pEyejQOgBo0p6ywIiLPllY
0t+jpNspHpAGfXID6oqjpYuJw3AfVRBlwnQEGBsIACoFgmQd6s0JkCH+Ofk7
gvsTApsMFiEElhMzIoyVB78iG1SiIf45+TuC+xMAAGgQuN9G73446ykvJ/mL
sCZ7zGFId2gBd1EnG0FTC4npfOKpck0X8dngByrCxU8LDSfvjsEp/xDAiKsQ
aU71tdtNBQ==
=e7jT
-----END PGP PRIVATE KEY BLOCK-----` });
    // sanity checks
    await expect(privateKey.validate()).to.be.fulfilled;
    const signingKey = await privateKey.getSigningKey();
    expect(signingKey.keyPacket.algorithm).to.equal(openpgp.enums.publicKey.ed25519);
    expect(signingKey.getAlgorithmInfo()).to.deep.equal({ algorithm: 'ed25519' });

    const encryptionKey = await privateKey.getEncryptionKey();
    expect(encryptionKey.keyPacket.algorithm).to.equal(openpgp.enums.publicKey.x25519);
    expect(encryptionKey.getAlgorithmInfo()).to.deep.equal({ algorithm: 'x25519' });
  });

  it('Parsing V4 key using curve448 format', async function() {
    const privateKey = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----

xX0GZRqLYhwAAAA52IEq/TpKiPp6RofQaq4uhCruTtiG+qiVFnwsQgeh0ui34kHD
Y1E04mBai0pCoDiFVokwsKt3F5sAAC8lDYfVP/p3atbXJDTJB2W9WmZxIS7pUGhS
bjlWpZB/OVTBsoIfP/2J+Hi4ESwBRfDUDgwK4aJVKsLAIAYfHAoAAAA/BQJlGoti
IqEGobsxt8WKsMuJWANyTXpWMdC1QN/7EyJClfcs+nBgqdUCGwMCHgkCCwcDFQoI
AhYABScHAwcCAAAAAPiGIG2qmhCULQ/+H4rKV0XEM1x0uVY3l878Pa6ijZLouZU/
VRd5PnbGyLPL++q3LDViUUdZ1uusRc01f677Q6wpUU90k8MH/oULwI0+KPtqe1N4
6nr1NTERsAmAaPjUdf4ZUXX/GWiTd/AlsS5JqGnAQxKRJkzCJacOTOElRMjzGUX7
CGaAnhSC86YRZ68ocTPfZysAzRdVc2VyQiA8VXNlckJAdGVzdC50ZXN0PsLADQYT
HAoAAAAsBQJlGotiIqEGobsxt8WKsMuJWANyTXpWMdC1QN/7EyJClfcs+nBgqdUC
GQEAAAAASKwgVzMoPb2Hbr3lbNI1CRWECokYLokL7F8MbYiMnlg+v6QXLdStvT13
ZjxdrWQAx3MbihSOUSXbdAys90yMOAdtognj+x418J/TaYFMtIGBHwoHv8gQVnx9
9ICv8ezx1T5VvGBYNuKZ5Ww0WPEpYMf1VA+Y9JxpohdcRenNBdSug4tLWla2y8NH
aO28Fltpb4AuGQDHewZlGotiGgAAADjdabr1ohAOnbSUUkVhtUM/LVdnYgDLhmaj
YZ1N7TWY0fqEpMk2LLo2165HOmhddRPeTB1TWbuwBwB8lKc3czFUzYcAgvZ08T5S
UUHjfIhjeJeY4yd0OZDfzPw1vbegCc7t94bT+XGoIQbC/Bl7HCyAiMLADQYYHAoA
AAAsBQJlGotiIqEGobsxt8WKsMuJWANyTXpWMdC1QN/7EyJClfcs+nBgqdUCGwwA
AAAAHh0gf2kdqLoXdFX+aNVORr5VCVgcm2gBw8l68lDJ1ftA71bMllFi6Q5sLPUr
6UCpJYYk3o3hYUYzIHmCIZGVYe1pxRgIUNqxydXEfzylJmN5NbiJNkjJizrI7oAR
1mIcEEb/hmRMOUs1V2mcGuoeALBI/r/SyqDE2GRjH6d6g1RS7ZARPPHlZlY4CTqC
4a7L+8odDwA=
=chx0
-----END PGP PRIVATE KEY BLOCK-----
    ` });
    // sanity checks
    await expect(privateKey.validate()).to.be.fulfilled;
    const signingKey = await privateKey.getSigningKey();
    expect(signingKey.keyPacket.algorithm).to.equal(openpgp.enums.publicKey.ed448);
    expect(signingKey.getAlgorithmInfo()).to.deep.equal({ algorithm: 'ed448' });

    const encryptionKey = await privateKey.getEncryptionKey();
    expect(encryptionKey.keyPacket.algorithm).to.equal(openpgp.enums.publicKey.x448);
    expect(encryptionKey.getAlgorithmInfo()).to.deep.equal({ algorithm: 'x448' });
  });

  it('Throw when parsing x448 key with unexpected secret param size', async function() {
    // x448 subkey with secret seed of 57 bytes instead of 56
    const armoredKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----

xXsEZRwKeRx0854v253kTyH54UIFSy3dLbMLTSIGh+UeC6IWXvxt2551rUee
wn9y5hJbJwm/f2eA3vkOUqhKbAAAy7hGpOu61AMTr6w9G9VLStDR9Int/vgi
cNSl1LTvF8f5lqBrpMFFPUHwi4igNMqb7I/c7J2Uc+4uInvNAMK3BBAcCgA7
BYJlHAp5AwsJBwmQ+2DdQup2xx8DFQgKAhYAAhkBApsDAh4BFiEE5NkqBdRy
GYLB7cPm+2DdQup2xx8AAIuONFkN6wRtRJA9EJvwhj7DkzNRjFNw8OE/ENzj
3XcN/WtZYCnLZ+ih9HSar9+CZzI+4mHtvOunq7sAjuvPbGndbbdg46DSy0Ac
wIVxSeIMNpwpktMyUx/ugIZeu7VvcnW4SbQOEB5KPlja/qjapWwg4wIAx3oE
ZRwKeRogjMz3j2jL4X1Zhk+i/EK09BTU/2zuYuB+Pl9Y+RKDaxuOmZ4zzx+S
xa/RYWEVKkcIY9pBAxd4RgDZs0rJP9DRIe69vix1Wd/LxuSctG2SMfcjzyAl
5mmCsb+sgubDduEBotTv3qFnNTYMUUHEFojWC4EfjcKmBBgcCgAqBYJlHAp5
CZD7YN1C6nbHHwKbDBYhBOTZKgXUchmCwe3D5vtg3ULqdscfAAD/uWh1fZy7
hMeb7552mWqB0eGXpOJR9K/rLDj8woLkXJMyyhfYU5PTwmRpowsGwbm7TMku
gXxMryvfgBDKTN8tkgJ4BJUsDDwU7aJE1fzOZ5TP4iNHpPOY1qqpmaAtTh6Q
PzIEeL7UH3trraFmi+Gq8u4kAA==
-----END PGP PRIVATE KEY BLOCK-----`;

    await expect(openpgp.readKey({ armoredKey })).to.be.rejectedWith(/Error reading MPIs/);
  });

  it('Testing key ID and fingerprint for V4 keys', async function() {
    const pubKeysV4 = await openpgp.readKeys({ armoredKeys: twoKeys });
    expect(pubKeysV4).to.exist;
    expect(pubKeysV4).to.have.length(2);

    const pubKeyV4 = pubKeysV4[0];
    expect(pubKeyV4).to.exist;

    expect(pubKeyV4.getKeyID().toHex()).to.equal('4a63613a4d6e4094');
    expect(pubKeyV4.getFingerprint()).to.equal('f470e50dcb1ad5f1e64e08644a63613a4d6e4094');
  });

  it('Create new key ID with fromID()', async function() {
    const [pubKeyV4] = await openpgp.readKeys({ armoredKeys: twoKeys });
    const keyID = pubKeyV4.getKeyID();
    const newKeyID = KeyID.fromID(keyID.toHex());
    expect(newKeyID.equals(keyID)).to.be.true;
  });

  it('Testing key method getSubkeys', async function() {
    const pubKey = await openpgp.readKey({ armoredKey: pub_sig_test });
    expect(pubKey).to.exist;

    const packetlist = await openpgp.PacketList.fromBinary(
      (await openpgp.unarmor(pub_sig_test)).data,
      util.constructAllowedPackets([...Object.values(openpgp).filter(packetClass => !!packetClass.tag)]),
      openpgp.config
    );

    const subkeyPackets = [packetlist[8], packetlist[11]];
    const subkeys = pubKey.getSubkeys();
    expect(subkeys).to.exist;
    expect(subkeys).to.have.length(2);
    expect(subkeys[0].getKeyID().equals(subkeyPackets[0].getKeyID())).to.be.true;
    expect(subkeys[1].getKeyID().equals(subkeyPackets[1].getKeyID())).to.be.true;
  });

  it('Verify status of revoked primary key', async function() {
    const pubKey = await openpgp.readKey({ armoredKey: pub_revoked_subkeys });
    await expect(pubKey.verifyPrimaryKey()).to.be.rejectedWith('Primary key is revoked');
  });

  it('Verify status of revoked subkey', async function() {
    const pubKey = await openpgp.readKey({ armoredKey: pub_sig_test });
    expect(pubKey).to.exist;
    expect(pubKey.subkeys).to.exist;
    expect(pubKey.subkeys).to.have.length(2);

    await expect(pubKey.subkeys[0].verify()).to.be.rejectedWith('Subkey is revoked');
  });

  it('Verify status of key with non-self revocation signature', async function() {
    const { rejectPublicKeyAlgorithms } = openpgp.config;
    openpgp.config.rejectPublicKeyAlgorithms = new Set();

    try {
      const pubKey = await openpgp.readKey({ armoredKey: key_with_revoked_third_party_cert });
      const [selfCertification] = await pubKey.verifyPrimaryUser();
      const publicSigningKey = await pubKey.getSigningKey();
      expect(selfCertification.keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex());
      expect(selfCertification.valid).to.be.true;

      const certifyingKey = await openpgp.readKey({ armoredKey: certifying_key });
      const certifyingSigningKey = await certifyingKey.getSigningKey(undefined, undefined, undefined, { ...openpgp.config, allowMissingKeyFlags: true });
      const signatures = await pubKey.verifyPrimaryUser([certifyingKey]);
      expect(signatures.length).to.equal(2);
      expect(signatures[0].keyID.toHex()).to.equal(publicSigningKey.getKeyID().toHex());
      expect(signatures[0].valid).to.be.null;
      expect(signatures[1].keyID.toHex()).to.equal(certifyingSigningKey.getKeyID().toHex());
      expect(signatures[1].valid).to.be.false;

      const { user } = await pubKey.getPrimaryUser();
      await expect(
        user.verifyCertificate(user.otherCertifications[0], [certifyingKey], undefined, { ...openpgp.config, allowMissingKeyFlags: true })
      ).to.be.rejectedWith('User certificate is revoked');
    } finally {
      openpgp.config.rejectPublicKeyAlgorithms = rejectPublicKeyAlgorithms;
    }
  });

  it('Verify primary key with authorized revocation key in a direct-key signature', async function() {
    const pubKey = await openpgp.readKey({ armoredKey: key_with_authorized_revocation_key_in_separate_sig });
    await pubKey.verifyPrimaryKey();
  });

  it('Verify certificate of key with future creation date', async function() {
    const pubKey = await openpgp.readKey({ armoredKey: key_created_2030 });
    const user = pubKey.users[0];
    await user.verifyCertificate(user.selfCertifications[0], [pubKey], pubKey.keyPacket.created, openpgp.config);
    const verifyAllResult = await user.verifyAllCertifications([pubKey], pubKey.keyPacket.created, openpgp.config);
    expect(verifyAllResult[0].valid).to.be.true;
    await user.verify(pubKey.keyPacket.created, openpgp.config);
  });

  it('Evaluate key flags to find valid encryption key packet', async function() {
    const pubKey = await openpgp.readKey({ armoredKey: pub_sig_test });
    // remove subkeys
    pubKey.subkeys = [];
    // primary key has only key flags for signing
    await expect(pubKey.getEncryptionKey()).to.be.rejectedWith('Could not find valid encryption key packet in key c076e634d32b498d');
  });

  it('should pad an ECDSA P-521 key with shorter secret key', async function() {
    const key = await openpgp.readKey({ armoredKey: shortP521Key, config: { enableParsingV5Entities: true } });
    // secret key should be padded
    expect(key.keyPacket.privateParams.d.length === 66);
    // sanity check
    await expect(key.validate()).to.be.fulfilled;
  });

  it('should not decrypt using a sign-only RSA key, unless explicitly configured', async function () {
    const key = await openpgp.readKey({ armoredKey: rsaSignOnly });

    await expect(openpgp.decrypt({
      message: await openpgp.readMessage({ armoredMessage: encryptedRsaSignOnly }),
      decryptionKeys: key
    })).to.be.rejectedWith(/No decryption key packets found/);

    await expect(openpgp.decrypt({
      message: await openpgp.readMessage({ armoredMessage: encryptedRsaSignOnly }),
      decryptionKeys: key,
      config: { allowInsecureDecryptionWithSigningKeys: true }
    })).to.be.fulfilled;
  });

  it('PrivateKey.getDecryptionKeys() - should throw for sign-only key', async function() {
    const key = await openpgp.readKey({ armoredKey: rsaSignOnly });
    await expect(key.getDecryptionKeys()).to.be.rejectedWith(/No decryption key packets found/);
  });

  it('Key.getExpirationTime()', async function() {
    const [, pubKey] = await openpgp.readKeys({ armoredKeys: twoKeys });
    expect(pubKey).to.exist;
    expect(pubKey).to.be.an.instanceof(openpgp.PublicKey);
    const expirationTime = await pubKey.getExpirationTime();
    expect(expirationTime.toISOString()).to.be.equal('2018-11-26T10:58:29.000Z');
  });

  it('Key.getExpirationTime() - expired key', async function() {
    const pubKey = await openpgp.readKey({ armoredKey: expiredKey });
    expect(pubKey).to.exist;
    expect(pubKey).to.be.an.instanceof(openpgp.PublicKey);
    const expirationTime = await pubKey.getExpirationTime();
    expect(expirationTime.toISOString()).to.be.equal('1970-01-01T00:22:18.000Z');
  });

  it('SubKey.getExpirationTime()', async function() {
    const [, pubKey] = await openpgp.readKeys({ armoredKeys: twoKeys });
    expect(pubKey).to.exist;
    expect(pubKey).to.be.an.instanceof(openpgp.PublicKey);
    const expirationTime = await pubKey.subkeys[0].getExpirationTime();
    expect(expirationTime.toISOString()).to.be.equal('2018-11-26T10:58:29.000Z');
  });

  it('Key.getExpirationTime() - never expiring key', async function() {
    const { minRSABits } = openpgp.config;
    try {
      openpgp.config.minRSABits = 1024;
      const privKey = await openpgp.readKey({ armoredKey: priv_key_2000_2008 });
      const expirationTime = await privKey.getExpirationTime();
      expect(expirationTime).to.equal(Infinity);
    } finally {
      openpgp.config.minRSABits = minRSABits;
    }
  });

  it('Key.getExpirationTime() - key expiration in direct-key signature', async function() {
    const privKey = await openpgp.readKey({ armoredKey: expiredPublicKeyThroughDirectSignature });
    const expirationTime = await privKey.getExpirationTime();
    expect(expirationTime.toISOString()).to.equal('2020-06-13T14:57:14.000Z');
  });

  it("decryptKey() - throw if key parameters don't correspond", async function() {
    const privateKey = await openpgp.readKey({ armoredKey: mismatchingKeyParams });
    await expect(openpgp.decryptKey({ privateKey, passphrase: 'userpass' })).to.be.rejectedWith('Key is invalid');
  });

  it("validate() - don't throw if key parameters correspond", async function() {
    const { privateKey: key } = await openpgp.generateKey({ userIDs: {}, curve: 'ed25519Legacy', format: 'object' });
    await expect(key.validate()).to.not.be.rejected;
  });

  it('validate() - throw if all-gnu-dummy key', async function() {
    const key = await openpgp.readKey({ armoredKey: gnuDummyKey });
    await expect(key.validate()).to.be.rejectedWith('Cannot validate an all-gnu-dummy key');
  });

  it('validate() - gnu-dummy primary key with signing subkey', async function() {
    const key = await openpgp.readKey({ armoredKey: gnuDummyKeySigningSubkey });
    await expect(key.validate()).to.not.be.rejected;
  });

  it('validate() - gnu-dummy primary key with encryption subkey', async function() {
    const key = await openpgp.readKey({ armoredKey: dsaGnuDummyKeyWithElGamalSubkey });
    await expect(key.validate()).to.not.be.rejected;
  });

  it('validate() - curve ed25519 (eddsa) cannot be used for ecdsa', async function() {
    const key = await openpgp.readKey({ armoredKey: eddsaKeyAsEcdsa });
    await expect(key.validate()).to.be.rejectedWith('Key is invalid');
  });

  it('validate() - should skip for AEAD-encrypted key (non-legacy)', async function() {
    const v4KeyWithAEAD = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----

xYMEZaAFFxYJKwYBBAHaRw8BAQdA/C3ybUC91HiWAGd/KtPtjmYwWk7VmB+X
GXhQY9yyZkf9CQEDCBpqDPXSr+aPAGoAsXz/V2uY7EE0Xlutx3MVMEbqWz6m
fRRUn3/mtGr+PCdj9bbl0rVK+fR62kTbwATUpNdL4rrt1cNgOTlDtq1ZCc0P
PGFlYWRAdGVzdC5jb20+wpsEEBYKAE0FgmWgBRcDCwkHCZB2ZM+malVbdgUV
CAoMDgQWAAIBAhkBApsDAh4JFiEE8e8z3IJRZ+bZze8ldmTPpmpVW3YNJwkD
BwMJAQcBCQIHAgAAplYBALLKSm4Q0dPoX4mBgEuOMgtAEewfyUhp8MJdJvCa
9KIMAP9f3Qxf4ykXQwgL/e1pn1nNQgiQ7x33LXQ2vHynPkOyDceIBGWgBRcS
CisGAQQBl1UBBQEBB0Bfk/JMj2ONL/1hi31q3OePnDHLmo8IsafeG0RZY8wF
OgMBCAf9CQEDCHS8bQidEDvkAP6LovPpHodzcF7F+zbKlJKTI3l6xK4t2Dj6
BIgBQov9zJ4OK2xFbyraXSLqStQJOQV7XBfIYKHYdIBtxj6cfTYtBMJ4BBgW
CgAqBYJloAUXCZB2ZM+malVbdgKbDBYhBPHvM9yCUWfm2c3vJXZkz6ZqVVt2
AAA+gQD9EpMMjlBFvvyACsKwQRmIqUNTfCy4uHL1Ee1fJ4ur9ZQBAP2CiOSN
CNa5yq6lyexhsn2Vs8DsX+SOSUyNJiy5FyIJ
-----END PGP PRIVATE KEY BLOCK-----` });
    const passphrase = 'passphrase';
    // sanity checks about key encryption mechanism
    expect(v4KeyWithAEAD.keyPacket.aead).to.not.be.null;
    expect(v4KeyWithAEAD.keyPacket.isLegacyAEAD).to.be.false;
    expect(v4KeyWithAEAD.keyPacket.usedModernAEAD).to.be.true;

    const decryptedKey = await openpgp.decryptKey({ privateKey: v4KeyWithAEAD, passphrase });
    decryptedKey.keyPacket.privateParams.seed = new Uint8Array(1); // corrupt key to confirm that the actual validation is skipped
    await expect(decryptedKey.validate()).to.be.fulfilled;
  });

  it('validate() - should be run if AEAD-encrypted key gets re-encrypted without AEAD', async function() {
    const v4KeyWithAEAD = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----

xYMEZaAFFxYJKwYBBAHaRw8BAQdA/C3ybUC91HiWAGd/KtPtjmYwWk7VmB+X
GXhQY9yyZkf9CQEDCBpqDPXSr+aPAGoAsXz/V2uY7EE0Xlutx3MVMEbqWz6m
fRRUn3/mtGr+PCdj9bbl0rVK+fR62kTbwATUpNdL4rrt1cNgOTlDtq1ZCc0P
PGFlYWRAdGVzdC5jb20+wpsEEBYKAE0FgmWgBRcDCwkHCZB2ZM+malVbdgUV
CAoMDgQWAAIBAhkBApsDAh4JFiEE8e8z3IJRZ+bZze8ldmTPpmpVW3YNJwkD
BwMJAQcBCQIHAgAAplYBALLKSm4Q0dPoX4mBgEuOMgtAEewfyUhp8MJdJvCa
9KIMAP9f3Qxf4ykXQwgL/e1pn1nNQgiQ7x33LXQ2vHynPkOyDceIBGWgBRcS
CisGAQQBl1UBBQEBB0Bfk/JMj2ONL/1hi31q3OePnDHLmo8IsafeG0RZY8wF
OgMBCAf9CQEDCHS8bQidEDvkAP6LovPpHodzcF7F+zbKlJKTI3l6xK4t2Dj6
BIgBQov9zJ4OK2xFbyraXSLqStQJOQV7XBfIYKHYdIBtxj6cfTYtBMJ4BBgW
CgAqBYJloAUXCZB2ZM+malVbdgKbDBYhBPHvM9yCUWfm2c3vJXZkz6ZqVVt2
AAA+gQD9EpMMjlBFvvyACsKwQRmIqUNTfCy4uHL1Ee1fJ4ur9ZQBAP2CiOSN
CNa5yq6lyexhsn2Vs8DsX+SOSUyNJiy5FyIJ
-----END PGP PRIVATE KEY BLOCK-----` });
    const passphrase = 'passphrase';
    // sanity checks about key encryption mechanism
    expect(v4KeyWithAEAD.keyPacket.aead).to.not.be.null;
    expect(v4KeyWithAEAD.keyPacket.isLegacyAEAD).to.be.false;
    expect(v4KeyWithAEAD.keyPacket.usedModernAEAD).to.be.true;

    const reEncryptedKey = await openpgp.encryptKey({
      privateKey: await openpgp.decryptKey({ privateKey: v4KeyWithAEAD, passphrase }),
      passphrase,
      config: { aeadProtect: false }
    });

    expect(reEncryptedKey.keyPacket.usedModernAEAD).to.be.false;
    const reDecryptedKey = await openpgp.decryptKey({ privateKey: reEncryptedKey, passphrase });
    reDecryptedKey.keyPacket.privateParams.seed = new Uint8Array(1); // corrupt key to confirm that the actual validation is now run
    await expect(reDecryptedKey.validate()).to.be.rejectedWith('Key is invalid');
  });

  it('isDecrypted() - should reflect whether all (sub)keys are encrypted', async function() {
    const passphrase = '12345678';
    const { privateKey: key } = await openpgp.generateKey({ userIDs: {}, curve: 'ed25519Legacy', passphrase, format: 'object' });
    expect(key.isDecrypted()).to.be.false;
    await key.subkeys[0].keyPacket.decrypt(passphrase);
    expect(key.isDecrypted()).to.be.true;
  });

  it('isDecrypted() - gnu-dummy primary key', async function() {
    const key = await openpgp.readKey({ armoredKey: gnuDummyKeySigningSubkey });
    expect(key.isDecrypted()).to.be.true;
    const encryptedKey = await openpgp.encryptKey({ privateKey: key, passphrase: '12345678' });
    expect(encryptedKey.isDecrypted()).to.be.false;
  });

  it('isDecrypted() - all-gnu-dummy key', async function() {
    const key = await openpgp.readKey({ armoredKey: gnuDummyKey });
    expect(key.isDecrypted()).to.be.false;
  });

  it('makeDummy() - the converted key can be parsed', async function() {
    const { privateKey: key } = await openpgp.generateKey({ userIDs: { name: 'dummy', email: 'dummy@alice.com' }, format: 'object' });
    key.keyPacket.makeDummy();
    const parsedKeys = await openpgp.readKey({ armoredKey: key.armor() });
    expect(parsedKeys).to.not.be.empty;
  });

  it('makeDummy() - the converted key can be encrypted and decrypted', async function() {
    const { privateKey: key } = await openpgp.generateKey({ userIDs: { name: 'dummy', email: 'dummy@alice.com' }, format: 'object' });
    const passphrase = 'passphrase';
    key.keyPacket.makeDummy();
    expect(key.isDecrypted()).to.be.true;
    const encryptedKey = await openpgp.encryptKey({ privateKey: key, passphrase });
    expect(encryptedKey.isDecrypted()).to.be.false;
    const decryptedKey = await openpgp.decryptKey({ privateKey: encryptedKey, passphrase });
    expect(decryptedKey.isDecrypted()).to.be.true;
  });

  it('makeDummy() - the converted key is valid but can no longer sign', async function() {
    const key = await openpgp.decryptKey({
      privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
      passphrase: 'hello world'
    });
    expect(key.keyPacket.isDummy()).to.be.false;
    key.keyPacket.makeDummy();
    expect(key.keyPacket.isDummy()).to.be.true;
    await key.validate();
    await expect(openpgp.reformatKey({ privateKey: key, userIDs: { name: 'test', email: 'a@b.com' } })).to.be.rejectedWith(/Cannot reformat a gnu-dummy primary key/);
  });

  it('makeDummy() - subkeys of the converted key can still sign', async function() {
    const key = await openpgp.decryptKey({
      privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
      passphrase: 'hello world'
    });
    expect(key.keyPacket.isDummy()).to.be.false;
    key.keyPacket.makeDummy();
    expect(key.keyPacket.isDummy()).to.be.true;
    await expect(openpgp.sign({ message: await openpgp.createMessage({ text: 'test' }), signingKeys: [key], config: { minRSABits: 1024 } })).to.be.fulfilled;
  });

  it('makeDummy() - should work for encrypted keys', async function() {
    const passphrase = 'hello world';
    const key = await openpgp.readKey({ armoredKey: priv_key_rsa });
    expect(key.keyPacket.isDummy()).to.be.false;
    key.keyPacket.makeDummy();
    expect(key.keyPacket.isDummy()).to.be.true;
    // dummy primary key should always be marked as not decrypted
    const decryptedKey = await openpgp.decryptKey({ privateKey: key, passphrase });
    expect(decryptedKey.keyPacket.isDummy()).to.be.true;
    expect(decryptedKey.keyPacket.isEncrypted === null);
    expect(decryptedKey.keyPacket.isDecrypted()).to.be.false;
    const encryptedKey = await openpgp.encryptKey({ privateKey: decryptedKey, passphrase });
    expect(encryptedKey.keyPacket.isDummy()).to.be.true;
    expect(encryptedKey.keyPacket.isEncrypted === null);
    expect(encryptedKey.keyPacket.isDecrypted()).to.be.false;
    // confirm that the converted keys can be parsed
    await openpgp.readKey({ armoredKey: encryptedKey.armor() });
    await openpgp.readKey({ armoredKey: decryptedKey.armor() });
  });

  it('makeDummy() - should work for encrypted keys with unknown s2k (unparseableKeyMaterial)', async function() {
    const key = await openpgp.readKey({ armoredKey: encryptedKeyUnknownS2K });
    expect(key.keyPacket.isDummy()).to.be.false;
    key.keyPacket.makeDummy();
    expect(key.keyPacket.isDummy()).to.be.true;
    expect(key.keyPacket.unparseableKeyMaterial).to.not.exist;
  });

  it('clearPrivateParams() - check that private key can no longer be used', async function() {
    const key = await openpgp.decryptKey({
      privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
      passphrase: 'hello world'
    });
    await key.clearPrivateParams();
    await expect(key.validate()).to.be.rejectedWith('Key is not decrypted');
  });

  it('clearPrivateParams() - detect that private key parameters were removed', async function() {
    const key = await openpgp.decryptKey({
      privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
      passphrase: 'hello world'
    });
    const signingKeyPacket = key.subkeys[0].keyPacket;
    const privateParams = signingKeyPacket.privateParams;
    await key.clearPrivateParams();
    key.keyPacket.isEncrypted = false;
    key.keyPacket.privateParams = privateParams;
    key.subkeys[0].keyPacket.isEncrypted = false;
    key.subkeys[0].keyPacket.privateParams = privateParams;
    await expect(key.validate()).to.be.rejectedWith('Key is invalid');
  });

  it('clearPrivateParams() - detect that private key parameters were zeroed out', async function() {
    const key = await openpgp.decryptKey({
      privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
      passphrase: 'hello world'
    });
    const signingKeyPacket = key.subkeys[0].keyPacket;
    const privateParams = {};
    Object.entries(signingKeyPacket.privateParams).forEach(([name, value]) => {
      privateParams[name] = value;
    });
    await key.clearPrivateParams();
    key.keyPacket.isEncrypted = false;
    key.keyPacket.privateParams = privateParams;
    key.subkeys[0].keyPacket.isEncrypted = false;
    key.subkeys[0].keyPacket.privateParams = privateParams;
    await expect(key.validate()).to.be.rejectedWith('Key is invalid');
  });

  it('update() - throw error if fingerprints not equal', async function() {
    const keys = await openpgp.readKeys({ armoredKeys: twoKeys });
    await expect(keys[0].update(keys[1])).to.be.rejectedWith(/Primary key fingerprints must be equal/);
  });

  it('update() - merge revocation signatures', async function() {
    const source = await openpgp.readKey({ armoredKey: pub_revoked_subkeys });
    const dest = await openpgp.readKey({ armoredKey: pub_revoked_subkeys });
    expect(source.revocationSignatures).to.exist;
    dest.revocationSignatures = [];
    return dest.update(source).then(updated => {
      expect(updated.revocationSignatures[0]).to.exist.and.be.an.instanceof(openpgp.SignaturePacket);
    });
  });

  it('update() - merge user', async function() {
    const source = await openpgp.readKey({ armoredKey: pub_sig_test });
    const dest = await openpgp.readKey({ armoredKey: pub_sig_test });
    expect(source.users[1]).to.exist;
    dest.users.pop();
    const updated = await dest.update(source);
    expect(updated.users[1]).to.exist;
    expect(updated.users[1].userID).to.equal(source.users[1].userID);
    expect(updated.users[1].selfCertifications.length).to.equal(source.users[1].selfCertifications.length);
    // check that the added users stores certifications separately
    updated.users[1].selfCertifications.pop();
    expect(updated.users[1].selfCertifications.length).to.not.equal(source.users[1].selfCertifications.length);
    // merge self-signatures
    const updatedAgain = await updated.update(source);
    expect(updatedAgain.users[1].selfCertifications.length).to.equal(source.users[1].selfCertifications.length);
  });

  it('update() - merge user - other and certification revocation signatures', async function() {
    const source = await openpgp.readKey({ armoredKey: pub_sig_test });
    const dest = await openpgp.readKey({ armoredKey: pub_sig_test });
    expect(source.users[1].otherCertifications).to.exist;
    expect(source.users[1].revocationSignatures).to.exist;
    dest.users[1].otherCertifications = [];
    dest.users[1].revocationSignatures.pop();
    return dest.update(source).then(updated => {
      expect(updated.users[1].otherCertifications).to.exist.and.to.have.length(1);
      expect(updated.users[1].otherCertifications[0].signature).to.equal(source.users[1].otherCertifications[0].signature);
      expect(updated.users[1].revocationSignatures).to.exist.and.to.have.length(2);
      expect(updated.users[1].revocationSignatures[1].signature).to.equal(source.users[1].revocationSignatures[1].signature);
    });
  });

  it('update() - merge subkey', async function() {
    const source = await openpgp.readKey({ armoredKey: pub_sig_test });
    const dest = await openpgp.readKey({ armoredKey: pub_sig_test });
    expect(source.subkeys[1]).to.exist;
    dest.subkeys.pop();
    const updated = await dest.update(source);
    expect(updated.subkeys[1]).to.exist;
    expect(
      updated.subkeys[1].getKeyID().toHex()
    ).to.equal(
      source.subkeys[1].getKeyID().toHex()
    );
    expect(updated.subkeys[1].bindingSignatures.length).to.equal(source.subkeys[1].bindingSignatures.length);
    // check that the added subkey stores binding signatures separately
    updated.subkeys[1].bindingSignatures.pop();
    expect(updated.subkeys[1].bindingSignatures.length).to.not.equal(source.subkeys[1].bindingSignatures.length);
    // merge binding signature
    const updatedAgain = await updated.update(source);
    expect(updatedAgain.subkeys[1].bindingSignatures.length).to.equal(source.subkeys[1].bindingSignatures.length);
  });

  it('update() - merge subkey - revocation signature', async function() {
    const source = await openpgp.readKey({ armoredKey: pub_sig_test });
    const dest = await openpgp.readKey({ armoredKey: pub_sig_test });
    expect(source.subkeys[0].revocationSignatures).to.exist;
    dest.subkeys[0].revocationSignatures = [];
    return dest.update(source).then(updated => {
      expect(updated.subkeys[0].revocationSignatures).to.exist;
      expect(updated.subkeys[0].revocationSignatures[0].signature).to.equal(updated.subkeys[0].revocationSignatures[0].signature);
    });
  });

  it('update() - merge private key into public key', async function() {
    const source = await openpgp.readKey({ armoredKey: priv_key_rsa });
    const [dest] = await openpgp.readKeys({ armoredKeys: twoKeys });
    expect(dest.isPrivate()).to.be.false;
    return dest.update(source).then(async updated => {
      expect(updated.isPrivate()).to.be.true;
      return Promise.all([
        updated.verifyPrimaryKey().then(async result => {
          await expect(source.verifyPrimaryKey()).to.eventually.equal(result);
        }),
        updated.users[0].verify(updated.keyPacket).then(async result => {
          await expect(source.users[0].verify(source.keyPacket)).to.eventually.equal(result);
        }),
        updated.subkeys[0].verify().then(async result => {
          await expect(source.subkeys[0].verify()).to.eventually.deep.equal(result);
        })
      ]);
    });
  });

  it('update() - merge private key into public key - no subkeys', async function() {
    const source = await openpgp.readKey({ armoredKey: priv_key_rsa });
    const [dest] = await openpgp.readKeys({ armoredKeys: twoKeys });
    source.subkeys = [];
    dest.subkeys = [];
    expect(dest.isPrivate()).to.be.false;

    const updated = await dest.update(source);
    expect(updated.isPrivate()).to.be.true;

    await updated.verifyPrimaryKey();
    await source.verifyPrimaryKey();

    await updated.users[0].verify(updated.keyPacket);
    await source.users[0].verify(source.keyPacket);
  });

  it('update() - merge private key into public key - mismatch throws error', async function() {
    const source = await openpgp.readKey({ armoredKey: priv_key_rsa });
    const [dest] = await openpgp.readKeys({ armoredKeys: twoKeys });
    source.subkeys = [];
    expect(dest.subkeys).to.exist;
    expect(dest.isPrivate()).to.be.false;
    await expect(dest.update(source))
      .to.be.rejectedWith('Cannot update public key with private key if subkeys mismatch');
  });

  it('update() - merge subkey binding signatures', async function() {
    const source = await openpgp.readKey({ armoredKey: pgp_desktop_pub });
    const dest = await openpgp.readKey({ armoredKey: pgp_desktop_priv });
    expect(source.subkeys[0].bindingSignatures[0]).to.exist;
    await source.subkeys[0].verify();
    expect(dest.subkeys[0].bindingSignatures[0]).to.not.exist;
    const updated = await dest.update(source);
    expect(updated.subkeys[0].bindingSignatures[0]).to.exist;
    // the source primary key should still verify the subkey
    updated.subkeys[0].mainKey = source;
    await updated.subkeys[0].verify();
    updated.subkeys[0].mainKey = updated;
  });

  it('update() - merge multiple subkey binding signatures', async function() {
    const source = await openpgp.readKey({ armoredKey: multipleBindingSignatures });
    const dest = await openpgp.readKey({ armoredKey: multipleBindingSignatures });
    // remove last subkey binding signature of destination subkey
    dest.subkeys[0].bindingSignatures.length = 1;
    expect((await source.subkeys[0].getExpirationTime()).toISOString()).to.equal('2015-10-18T07:41:30.000Z');
    expect((await dest.subkeys[0].getExpirationTime()).toISOString()).to.equal('2018-09-07T06:03:37.000Z');
    return dest.update(source).then(async updated => {
      expect(updated.subkeys[0].bindingSignatures.length).to.equal(1);
      // destination key gets new expiration date from source key which has newer subkey binding signature
      expect((await updated.subkeys[0].getExpirationTime()).toISOString()).to.equal('2015-10-18T07:41:30.000Z');
    });
  });

  it('clone() - removing users or their signatures does not affect the original key', async function() {
    const key = await openpgp.readKey({ armoredKey: priv_key_rsa });
    const keyClone = key.clone();
    expect(key.users[0].selfCertifications.length > 0).to.be.true;
    expect(keyClone.users[0].selfCertifications.length > 0).to.be.true;
    keyClone.users[0].selfCertifications = [];
    expect(key.users[0].selfCertifications.length > 0).to.be.true;
    expect(keyClone.users[0].selfCertifications.length > 0).to.be.false;
  });

  it('clone() - removing subkeys or their signatures does not affect the original key', async function() {
    const key = await openpgp.readKey({ armoredKey: priv_key_rsa });
    const keyClone = key.clone(true);
    expect(key.subkeys[0].bindingSignatures.length > 0).to.be.true;
    expect(keyClone.subkeys[0].bindingSignatures.length > 0).to.be.true;
    keyClone.subkeys[0].bindingSignatures = [];
    expect(key.subkeys[0].bindingSignatures.length > 0).to.be.true;
    expect(keyClone.subkeys[0].bindingSignatures.length > 0).to.be.false;
  });

  it('revoke() - primary key', async function() {
    const privKey = await openpgp.decryptKey({
      privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
      passphrase: 'hello world'
    });

    await privKey.revoke({
      flag: openpgp.enums.reasonForRevocation.keyRetired,
      string: 'Testing key revocation'
    }).then(async revKey => {
      expect(revKey.revocationSignatures).to.exist.and.have.length(1);
      expect(revKey.revocationSignatures[0].signatureType).to.equal(openpgp.enums.signature.keyRevocation);
      expect(revKey.revocationSignatures[0].reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.keyRetired);
      expect(revKey.revocationSignatures[0].reasonForRevocationString).to.equal('Testing key revocation');

      await privKey.verifyPrimaryKey();
      await expect(revKey.verifyPrimaryKey()).to.be.rejectedWith('Primary key is revoked');
    });
  });

  it('revoke() - subkey', async function() {
    const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
    const privKey = await openpgp.decryptKey({
      privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
      passphrase: 'hello world'
    });

    const subkey = pubKey.subkeys[0];
    await subkey.revoke(privKey.keyPacket, {
      flag: openpgp.enums.reasonForRevocation.keySuperseded
    }).then(async revKey => {
      expect(revKey.revocationSignatures).to.exist.and.have.length(1);
      expect(revKey.revocationSignatures[0].signatureType).to.equal(openpgp.enums.signature.subkeyRevocation);
      expect(revKey.revocationSignatures[0].reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.keySuperseded);
      expect(revKey.revocationSignatures[0].reasonForRevocationString).to.equal('');

      await subkey.verify();
      await expect(revKey.verify()).to.be.rejectedWith('Subkey is revoked');
    });
  });

  it('revoke() - user', async function() {
    const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm2 });
    const privKey = await openpgp.decryptKey({
      privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }),
      passphrase: 'hello world'
    });

    const user = pubKey.users[0];
    await user.revoke(privKey.keyPacket, {
      flag: openpgp.enums.reasonForRevocation.userIDInvalid
    }).then(async revUser => {
      expect(user.userID.equals(revUser.userID)).to.be.true;
      expect(revUser.revocationSignatures).to.exist.and.have.length(1);
      expect(revUser.revocationSignatures[0].signatureType).to.equal(openpgp.enums.signature.certRevocation);
      expect(revUser.revocationSignatures[0].reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.userIDInvalid);
      expect(revUser.revocationSignatures[0].reasonForRevocationString).to.equal('');

      await user.verify();
      await expect(revUser.verify()).to.be.rejectedWith('Self-certification is revoked');
    });
  });

  it('applyRevocationCertificate() should produce the same revoked key as GnuPG', async function() {
    const pubKey = await openpgp.readKey({ armoredKey: pub_key_arm4 });

    return pubKey.applyRevocationCertificate(revocation_certificate_arm4).then(async revKey => {
      expect(revKey.armor()).to.equal((await openpgp.readKey({ armoredKey: revoked_key_arm4 })).armor());
    });
  });

  it('getRevocationCertificate() should produce the same revocation certificate as GnuPG', async function() {
    const revKey = await openpgp.readKey({ armoredKey: revoked_key_arm4 });
    const revocationCertificate = await revKey.getRevocationCertificate();

    const input = await openpgp.unarmor(revocation_certificate_arm4);
    const packetlist = await openpgp.PacketList.fromBinary(input.data, util.constructAllowedPackets([openpgp.SignaturePacket]), openpgp.config);
    const armored = openpgp.armor(openpgp.enums.armor.publicKey, packetlist.write(), undefined, undefined, undefined, true);

    expect(revocationCertificate.replace(/^Comment: .*$\n/mg, '')).to.equal(armored.replace(/^Comment: .*$\n/mg, ''));
  });

  it('getRevocationCertificate() should have an appropriate comment', async function() {
    const revKey = await openpgp.readKey({ armoredKey: revoked_key_arm4 });
    const revocationCertificate = await revKey.getRevocationCertificate();

    expect(revocationCertificate).to.match(/Comment: This is a revocation certificate/);
    expect(revKey.armor()).not.to.match(/Comment: This is a revocation certificate/);
  });

  describe('getPreferredCipherSuite()', () => {
    it('getPreferredCipherSuite - one key', async function() {
      const [key1] = await openpgp.readKeys({ armoredKeys: twoKeys });
      const { symmetricAlgo, aeadAlgo } = await getPreferredCipherSuite([key1], undefined, undefined, {
        ...openpgp.config, preferredSymmetricAlgorithm: openpgp.enums.symmetric.aes256
      });
      expect(symmetricAlgo).to.equal(openpgp.enums.symmetric.aes256);
      expect(aeadAlgo).to.equal(undefined);
    });

    it('getPreferredCipherSuite - two keys', async function() {
      const { aes128, aes192, cast5 } = openpgp.enums.symmetric;
      const [key1, key2] = await openpgp.readKeys({ armoredKeys: twoKeys });
      const primaryUser = await key2.getPrimaryUser();
      primaryUser.selfCertification.preferredSymmetricAlgorithms = [6, aes192, cast5];
      const { symmetricAlgo, aeadAlgo } = await getPreferredCipherSuite([key1, key2], undefined, undefined, {
        ...openpgp.config, preferredSymmetricAlgorithm: openpgp.enums.symmetric.aes192
      });
      expect(symmetricAlgo).to.equal(aes192);
      expect(aeadAlgo).to.equal(undefined);
      const { symmetricAlgo: symmetricAlgo2, aeadAlgo: aeadAlgo2 } = await getPreferredCipherSuite([key1, key2], undefined, undefined, {
        ...openpgp.config, preferredSymmetricAlgorithm: openpgp.enums.symmetric.aes256
      });
      expect(symmetricAlgo2).to.equal(aes128);
      expect(aeadAlgo2).to.equal(undefined);
    });

    it('getPreferredCipherSuite - two keys - one without pref', async function() {
      const [key1, key2] = await openpgp.readKeys({ armoredKeys: twoKeys });
      const primaryUser = await key2.getPrimaryUser();
      primaryUser.selfCertification.preferredSymmetricAlgorithms = null;
      const { symmetricAlgo, aeadAlgo } = await getPreferredCipherSuite([key1, key2]);
      expect(symmetricAlgo).to.equal(openpgp.enums.symmetric.aes128);
      expect(aeadAlgo).to.equal(undefined);
    });

    it('getPreferredCipherSuite with AEAD - one key - GCM', async function() {
      const [key1] = await openpgp.readKeys({ armoredKeys: twoKeys });
      const primaryUser = await key1.getPrimaryUser();
      primaryUser.selfCertification.features = [9]; // Monkey-patch SEIPDv2 feature flag
      primaryUser.selfCertification.preferredCipherSuites = [[9, 3], [9, 2]];
      const { symmetricAlgo, aeadAlgo } = await getPreferredCipherSuite([key1], undefined, undefined, {
        ...openpgp.config,
        aeadProtect: true,
        preferredAEADAlgorithm: openpgp.enums.aead.gcm
      });
      expect(symmetricAlgo).to.equal(openpgp.enums.symmetric.aes256);
      expect(aeadAlgo).to.equal(openpgp.enums.aead.gcm);
    });

    it('getPreferredCipherSuite with AEAD - one key - AES256-OCB', async function() {
      const [key1] = await openpgp.readKeys({ armoredKeys: twoKeys });
      const primaryUser = await key1.getPrimaryUser();
      primaryUser.selfCertification.features = [9]; // Monkey-patch SEIPDv2 feature flag
      primaryUser.selfCertification.preferredCipherSuites = [[openpgp.enums.symmetric.aes256, openpgp.enums.aead.ocb]];
      const { symmetricAlgo, aeadAlgo } = await getPreferredCipherSuite([key1], undefined, undefined, {
        ...openpgp.config,
        aeadProtect: true,
        preferredAEADAlgorithm: openpgp.enums.aead.gcm
      });
      expect(symmetricAlgo).to.equal(openpgp.enums.symmetric.aes256);
      expect(aeadAlgo).to.equal(openpgp.enums.aead.ocb);
    });

    it('getPreferredCipherSuite with AEAD - one key - AES128-GCM', async function() {
      const [key1] = await openpgp.readKeys({ armoredKeys: twoKeys });
      const primaryUser = await key1.getPrimaryUser();
      primaryUser.selfCertification.features = [9]; // Monkey-patch SEIPDv2 feature flag
      primaryUser.selfCertification.preferredCipherSuites = [[openpgp.enums.symmetric.aes128, openpgp.enums.aead.gcm]];
      const { symmetricAlgo, aeadAlgo } = await getPreferredCipherSuite([key1], undefined, undefined, {
        ...openpgp.config,
        aeadProtect: true,
        preferredAEADAlgorithm: openpgp.enums.aead.gcm
      });
      expect(symmetricAlgo).to.equal(openpgp.enums.symmetric.aes128);
      expect(aeadAlgo).to.equal(openpgp.enums.aead.gcm);
    });

    it('getPreferredCipherSuite with AEAD - two keys - one without pref', async function() {
      const keys = await openpgp.readKeys({ armoredKeys: twoKeys });
      const key1 = keys[0];
      const key2 = keys[1];
      const primaryUser = await key1.getPrimaryUser();
      primaryUser.selfCertification.features = [9]; // Monkey-patch SEIPDv2 feature flag
      primaryUser.selfCertification.preferredCipherSuites = [[9, 3], [9, 2]];
      const primaryUser2 = await key2.getPrimaryUser();
      primaryUser2.selfCertification.features = [9]; // Monkey-patch SEIPDv2 feature flag
      const { symmetricAlgo, aeadAlgo } = await getPreferredCipherSuite([key1, key2], undefined, undefined, {
        ...openpgp.config,
        aeadProtect: true
      });
      expect(symmetricAlgo).to.equal(openpgp.enums.symmetric.aes128);
      expect(aeadAlgo).to.equal(openpgp.enums.aead.ocb);
    });

    it('getPreferredCipherSuite with AEAD - two keys - one with no support', async function() {
      const keys = await openpgp.readKeys({ armoredKeys: twoKeys });
      const key1 = keys[0];
      const key2 = keys[1];
      const primaryUser = await key1.getPrimaryUser();
      primaryUser.selfCertification.features = [9]; // Monkey-patch SEIPDv2 feature flag
      primaryUser.selfCertification.preferredCipherSuites = [[9, 3], [9, 2]];
      const { symmetricAlgo, aeadAlgo } = await getPreferredCipherSuite([key1, key2], undefined, undefined, {
        ...openpgp.config,
        aeadProtect: true
      });
      expect(symmetricAlgo).to.equal(openpgp.enums.symmetric.aes256);
      expect(aeadAlgo).to.equal(undefined);
    });
  });

  describe('getPreferredHashAlgo()', () => {
    it('getPreferredHashAlgo - it can handle unknown hash algorithms', async function() {
      // Preferred hash algo: SHA256 and unknown algo with ID '99'
      const signingKeyWithUnknownAlgoPref = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----

xVgEZyJrexYJKwYBBAHaRw8BAQdAJwddYhjAmI6OzqxkW9cAXVBfZdSFxsaZ
0v9YAJA50fQAAQCK5y2PWn5MEoWnMre7WDMCv3HPs92No9r7ZrmXED3ZohDT
zQ48dGVzdEB0ZXN0Lml0PsLAEQQTFgoAgwWCZyJrewMLCQcJkPu0BwaBSfbo
RRQAAAAAABwAIHNhbHRAbm90YXRpb25zLm9wZW5wZ3Bqcy5vcmdJHbHl9Kh1
AmD2A1I0IgJEsWl12eWrRzU2C5MilKZDXQMVCGMEFgACAQIZAQKbAwIeARYh
BDc1TCI+j6hTVaLvtfu0BwaBSfboAAA3cwEAwA/JVtszZ1PgowLYG2/ok+WL
+AcEbvhPBBoJV6B2gLsA/2S/WIFiNLJd9xVPCsnlsh6GSqjNjEYXZIag0u14
WoEKx10EZyJrexIKKwYBBAGXVQEFAQEHQEnAXen/dnz9PZ+oJ9BYrDV+N/6y
c5nTJbTmMj01obBBAwEIBwAA/0izDCturSN2513OhRlrHc55biP/GL2CR6LK
e3Zo4XCoEFDCvgQYFgoAcAWCZyJrewmQ+7QHBoFJ9uhFFAAAAAAAHAAgc2Fs
dEBub3RhdGlvbnMub3BlbnBncGpzLm9yZ6bxx8jT55ZC4ZuKBMyd1j0ULyQ4
PPAbypPTzwI7bN7zApsMFiEENzVMIj6PqFNVou+1+7QHBoFJ9ugAAPRMAP9k
45AQSzIKF8JmS28I8hSUDrPCjSVh1A3Aw01F6sRYLgEA1wq81Sxnmvo6ztxK
EVdFOaJsHYaJ0A23hIaCWML5nAs=
=jJaL
-----END PGP PRIVATE KEY BLOCK-----
` });
      const config = {
        ...openpgp.config,
        preferredHashAlgorithm: openpgp.enums.hash.sha512 // SHA512 is not in the key prefs
      };
      const hashAlgo = await getPreferredHashAlgo(
        [signingKeyWithUnknownAlgoPref],
        signingKeyWithUnknownAlgoPref,
        undefined,
        undefined,
        config
      );
      expect(hashAlgo).to.equal(openpgp.enums.hash.sha256);
    });
  });

  it('User attribute packet read & write', async function() {
    const key = await openpgp.readKey({ armoredKey: user_attr_key });
    const key2 = await openpgp.readKey({ armoredKey: key.armor() });
    expect(key.users[1].userAttribute).eql(key2.users[1].userAttribute);
  });

  it('getPrimaryUser()', async function() {
    const key = await openpgp.readKey({ armoredKey: pub_sig_test });
    const primUser = await key.getPrimaryUser();
    expect(primUser).to.exist;
    expect(primUser.user.userID.userID).to.equal('Signature Test <signature@test.com>');
    expect(primUser.user.userID.name).to.equal('Signature Test');
    expect(primUser.user.userID.email).to.equal('signature@test.com');
    expect(primUser.user.userID.comment).to.equal('');
    expect(primUser.selfCertification).to.be.an.instanceof(openpgp.SignaturePacket);
  });

  it('getPrimaryUser() should throw if no UserIDs are bound', async function() {
    const keyWithoutUserID = `-----BEGIN PGP PRIVATE KEY BLOCK-----

xVgEWxpFkRYJKwYBBAHaRw8BAQdAYjjZLkp4qG7KAqJeVQlxQT6uCPq6rylV02nC
c6D/a8YAAP0YtS4UeLzeJGSgjGTlvSd3TWEsjxdGyzwfHCOejXMRbg2+zSFVbmJv
dW5kIFVJRCA8dW5ib3VuZEBleGFtcGxlLm9yZz7HXQRbGkWREgorBgEEAZdVAQUB
AQdAfxbFuoNlm5KfoqaWICETfMljzVTDAtiSM0TYSHzGAz8DAQoJAAD/cuu7bxUE
goBAhIyVH+pmvWpuDJbfu1Vaj5KiQxsKxJgP/MJ+BBgWCgAwApsMBYJbGkWRBYkB
3+IAFqEE30YL4fxJBMTm8ONLPOiTkVxEIS8JkDzok5FcRCEvAABb+gEAnQb/rMLO
Vz/bMCJoAShgybW1r6kRWejybzIjFSLnx/YA/iLZeo5UNdlXRJco+15RbFiNSAbw
VYGdb3eNlV8CfoEC
=FYbP
-----END PGP PRIVATE KEY BLOCK-----`;
    const key = await openpgp.readKey({ armoredKey: keyWithoutUserID });
    await expect(key.getPrimaryUser()).to.be.rejectedWith('Could not find valid self-signature in key 3ce893915c44212f');
  });

  it('Generate session key - latest created user', async function() {
    const publicKey = await openpgp.readKey({ armoredKey: multi_uid_key });
    // Set second user to prefer aes128. We should select this user by default, since it was created later.
    publicKey.users[1].selfCertifications[0].preferredSymmetricAlgorithms = [openpgp.enums.symmetric.aes128];
    const sessionKey = await openpgp.generateSessionKey({ encryptionKeys: publicKey });
    expect(sessionKey.algorithm).to.equal('aes128');
  });

  it('Generate session key - primary user', async function() {
    const publicKey = await openpgp.readKey({ armoredKey: multi_uid_key });
    // Set first user to primary. We should select this user by default.
    publicKey.users[0].selfCertifications[0].isPrimaryUserID = true;
    // Set first user to prefer aes128.
    publicKey.users[0].selfCertifications[0].preferredSymmetricAlgorithms = [openpgp.enums.symmetric.aes128];
    const sessionKey = await openpgp.generateSessionKey({ encryptionKeys: publicKey });
    expect(sessionKey.algorithm).to.equal('aes128');
  });

  it('Generate session key - specific user', async function() {
    const publicKey = await openpgp.readKey({ armoredKey: multi_uid_key });
    const privateKey = await openpgp.decryptKey({
      privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
      passphrase: 'hello world'
    });
    // Set first user to primary. We won't select this user, this is to test that.
    publicKey.users[0].selfCertifications[0].isPrimaryUserID = true;
    // Set second user to prefer aes128. We will select this user.
    publicKey.users[1].selfCertifications[0].preferredSymmetricAlgorithms = [openpgp.enums.symmetric.aes128];
    const sessionKey = await openpgp.generateSessionKey({ encryptionKeys: publicKey, encryptionUserIDs: { name: 'Test User', email: 'b@c.com' } });
    expect(sessionKey.algorithm).to.equal('aes128');
    const config = { minRSABits: 1024 };
    await openpgp.encrypt({
      message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: publicKey, signingKeys: privateKey, encryptionUserIDs: { name: 'Test User', email: 'b@c.com' }, format: 'binary', config
    });
    await expect(openpgp.encrypt({
      message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: publicKey, signingKeys: privateKey, encryptionUserIDs: { name: 'Test User', email: 'c@c.com' }, format: 'binary', config
    })).to.be.rejectedWith('Could not find user that matches that user ID');
  });

  it('Fails to encrypt to User ID-less key', async function() {
    const publicKey = await openpgp.readKey({ armoredKey: uidlessKey });
    expect(publicKey.users.length).to.equal(0);
    const privateKey = await openpgp.decryptKey({
      privateKey: await openpgp.readKey({ armoredKey: uidlessKey }),
      passphrase: 'correct horse battery staple'
    });
    await expect(openpgp.encrypt({ message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: publicKey, signingKeys: privateKey, format: 'binary' })).to.be.rejectedWith('Could not find primary user');
  });

  it('Sign - specific user', async function() {
    const publicKey = await openpgp.readKey({ armoredKey: multi_uid_key });
    const privateKey = await openpgp.decryptKey({
      privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
      passphrase: 'hello world'
    });
    const privateKeyClone = await openpgp.readKey({ armoredKey: priv_key_rsa });
    // Duplicate user
    privateKey.users.push(privateKeyClone.users[0]);
    // Set first user to primary. We won't select this user, this is to test that.
    privateKey.users[0].selfCertifications[0].isPrimaryUserID = true;
    // Change userID of the first user so that we don't select it. This also makes this user invalid.
    privateKey.users[0].userID = openpgp.UserIDPacket.fromObject({ name: 'Test User', email: 'b@c.com' });
    // Set second user to prefer aes128. We will select this user.
    privateKey.users[1].selfCertifications[0].preferredHashAlgorithms = [openpgp.enums.hash.sha512];
    const config = { minRSABits: 1024, preferredHashAlgorithm: openpgp.enums.hash.sha512 };
    const signed = await openpgp.sign({
      message: await openpgp.createMessage({ text: 'hello' }), signingKeys: privateKey, signingUserIDs: { name: 'Test McTestington', email: 'test@example.com' }, format: 'binary', config
    });
    const signature = await openpgp.readMessage({ binaryMessage: signed });
    expect(signature.packets[0].hashAlgorithm).to.equal(openpgp.enums.hash.sha512);
    const encrypted = await openpgp.encrypt({
      message: await openpgp.createMessage({ text: 'hello' }), passwords: 'test', signingKeys: privateKey, signingUserIDs: { name: 'Test McTestington', email: 'test@example.com' }, format: 'binary', config
    });
    const { signatures } = await openpgp.decrypt({ message: await openpgp.readMessage({ binaryMessage: encrypted }), passwords: 'test' });
    expect((await signatures[0].signature).packets[0].hashAlgorithm).to.equal(openpgp.enums.hash.sha512);
    await expect(openpgp.encrypt({
      message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: publicKey, signingKeys: privateKey, signingUserIDs: { name: 'Not Test McTestington', email: 'test@example.com' }, format: 'binary', config
    })).to.be.rejectedWith('Could not find user that matches that user ID');
  });

  it('Find a valid subkey binding signature among many invalid ones', async function() {
    const key = await openpgp.readKey({ armoredKey: valid_binding_sig_among_many_expired_sigs_pub });
    expect(await key.getEncryptionKey(undefined, undefined, undefined, { ...openpgp.config, minRSABits: 1024 })).to.not.be.null;
  });

  it('Selects the most recent subkey binding signature', async function() {
    const key = await openpgp.readKey({ armoredKey: multipleBindingSignatures });
    expect((await key.subkeys[0].getExpirationTime()).toISOString()).to.equal('2015-10-18T07:41:30.000Z');
  });

  it('Selects the most recent non-expired subkey binding signature', async function() {
    const key = await openpgp.readKey({ armoredKey: multipleBindingSignatures });
    key.subkeys[0].bindingSignatures[1].signatureNeverExpires = false;
    key.subkeys[0].bindingSignatures[1].signatureExpirationTime = 0;
    expect((await key.subkeys[0].getExpirationTime()).toISOString()).to.equal('2018-09-07T06:03:37.000Z');
  });

  it('Selects the most recent valid subkey binding signature', async function() {
    const key = await openpgp.readKey({ armoredKey: multipleBindingSignatures });
    key.subkeys[0].bindingSignatures[1].signatureData[0]++;
    expect((await key.subkeys[0].getExpirationTime()).toISOString()).to.equal('2018-09-07T06:03:37.000Z');
  });

  it('Handles a key with no valid subkey binding signatures gracefully', async function() {
    const key = await openpgp.readKey({ armoredKey: multipleBindingSignatures });
    key.subkeys[0].bindingSignatures[0].signatureData[0]++;
    key.subkeys[0].bindingSignatures[1].signatureData[0]++;
    expect(await key.subkeys[0].getExpirationTime()).to.be.null;
  });

  it('Reject encryption with revoked primary user', async function() {
    const key = await openpgp.readKey({ armoredKey: pub_revoked_subkeys });
    return openpgp.encrypt({ encryptionKeys: [key], message: await openpgp.createMessage({ text: 'random data' }) }).then(() => {
      throw new Error('encryptSessionKey should not encrypt with revoked public key');
    }).catch(function(error) {
      expect(error.message).to.equal('Error encrypting message: Primary user is revoked');
    });
  });

  it('Reject encryption with revoked subkey', async function() {
    const key = await openpgp.readKey({ armoredKey: pub_revoked_subkeys });
    key.revocationSignatures = [];
    key.users[0].revocationSignatures = [];
    const subkeyRevocationTime = key.subkeys[0].revocationSignatures[0].created;
    return openpgp.encrypt({ encryptionKeys: [key], message: await openpgp.createMessage({ text: 'random data' }), date: subkeyRevocationTime }).then(() => {
      throw new Error('encryptSessionKey should not encrypt with revoked public key');
    }).catch(error => {
      expect(error.message).to.equal('Error encrypting message: Could not find valid encryption key packet in key ' + key.getKeyID().toHex() + ': Subkey is revoked');
    });
  });

  it('Reject encryption with key revoked with appended revocation cert', async function() {
    const key = await openpgp.readKey({ armoredKey: pub_revoked_with_cert });
    await expect(
      openpgp.encrypt({ encryptionKeys: [key], message: await openpgp.createMessage({ text: 'random data' }) })
    ).to.be.rejectedWith(/Primary key is revoked/);
  });

  it('Merge key with another key with non-ID user attributes', async function() {
    const key = await openpgp.readKey({ armoredKey: mergeKey1 });
    const updateKey = await openpgp.readKey({ armoredKey: mergeKey2 });
    expect(key).to.exist;
    expect(updateKey).to.exist;
    expect(key.users).to.have.length(1);
    return key.update(updateKey).then(updated => {
      expect(updated.getFingerprint()).to.equal(updateKey.getFingerprint());
      expect(updated.users).to.have.length(2);
      expect(updated.users[1].userID).to.be.null;
    });
  });

  it("Should throw when trying to encrypt a key that's already encrypted", async function() {
    const passphrase = 'hello world';
    const key = await openpgp.readKey({ armoredKey: priv_key_rsa });
    const decryptedKey = await openpgp.decryptKey({ privateKey: key, passphrase });
    const encryptedKey = await openpgp.encryptKey({ privateKey: decryptedKey, passphrase });
    await expect(openpgp.encryptKey({ privateKey: encryptedKey, passphrase })).to.be.eventually.rejectedWith(/Key packet is already encrypted/);
  });

  describe('addSubkey functionality testing', function() {
    const rsaBits = 1024;
    let minRSABits;
    beforeEach(function() {
      minRSABits = openpgp.config.minRSABits;
      openpgp.config.minRSABits = rsaBits;
    });
    afterEach(function() {
      openpgp.config.minRSABits = minRSABits;
    });

    it('create and add a new rsa subkey to stored rsa key', async function() {
      const privateKey = await openpgp.decryptKey({
        privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
        passphrase: 'hello world'
      });
      const total = privateKey.subkeys.length;
      let newPrivateKey = await privateKey.addSubkey({ type: 'rsa' });
      const armoredKey = newPrivateKey.armor();
      newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey });
      const subkey = newPrivateKey.subkeys[total];
      expect(subkey).to.exist;
      expect(newPrivateKey.subkeys.length).to.be.equal(total + 1);
      const subkeyN = subkey.keyPacket.publicParams.n;
      const pkN = privateKey.keyPacket.publicParams.n;
      expect(subkeyN.length).to.be.equal(pkN.length);
      expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('rsaEncryptSign');
      expect(subkey.getAlgorithmInfo().bits).to.be.equal(privateKey.getAlgorithmInfo().bits);
      await subkey.verify();
    });

    it('Add a new default subkey to an rsaSign key', async function() {
      const userID = { name: 'test', email: 'a@b.com' };
      const opt = { type: 'rsa', rsaBits, userIDs: [userID], format: 'object', subkeys: [] };
      const { privateKey: key } = await openpgp.generateKey(opt);
      expect(key.subkeys).to.have.length(0);
      key.getAlgorithmInfo().algorithm = 'rsaSign';
      const newKey = await key.addSubkey();
      expect(newKey.subkeys[0].getAlgorithmInfo().algorithm).to.equal('rsaEncryptSign');
    });

    it('Add a new default subkey to an ecc key', async function() {
      const userID = { name: 'test', email: 'a@b.com' };
      const opt = { type: 'ecc', userIDs: [userID], format: 'object', subkeys: [] };
      const { privateKey: key } = await openpgp.generateKey(opt);
      expect(key.subkeys).to.have.length(0);
      const newKey = await key.addSubkey();
      expect(newKey.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh');
      expect(newKey.subkeys[0].getAlgorithmInfo().curve).to.equal('curve25519Legacy');
    });

    it('Add a new default subkey to an Ed488 key', async function() {
      const userID = { name: 'test', email: 'a@b.com' };
      const opt = { type: 'curve448', userIDs: [userID], format: 'object', subkeys: [] };
      const { privateKey: key } = await openpgp.generateKey(opt);
      expect(key.subkeys).to.have.length(0);
      const keyWithNewSubkey = await key.addSubkey();
      const parsedNewKey = await openpgp.readKey({ armoredKey: keyWithNewSubkey.armor() });
      expect(parsedNewKey.subkeys[0].getAlgorithmInfo().algorithm).to.equal('x448');
      expect(parsedNewKey.subkeys[0].getAlgorithmInfo().curve).to.be.undefined;
    });

    it('Add a new default subkey to a v6 key', async function() {
      const userID = { name: 'test', email: 'a@b.com' };
      const opt = { type: 'curve25519', userIDs: [userID], format: 'object', subkeys: [], config: { v6Keys: true } };
      const { privateKey: key } = await openpgp.generateKey(opt);
      expect(key.subkeys).to.have.length(0);
      const newKey = await key.addSubkey();
      expect(newKey.subkeys[0].keyPacket.version).to.equal(6);
      expect(newKey.subkeys[0].getAlgorithmInfo().algorithm).to.equal('x25519');
      expect(newKey.subkeys[0].getAlgorithmInfo().curve).to.be.undefined;
    });

    it('Add a new default subkey to a dsa key', async function() {
      const key = await openpgp.readKey({ armoredKey: dsaPrivateKey });
      const total = key.subkeys.length;
      const newKey = await key.addSubkey();
      expect(newKey.subkeys[total].getAlgorithmInfo().algorithm).to.equal('rsaEncryptSign');
      expect(newKey.subkeys[total].getAlgorithmInfo().bits).to.equal(Math.max(key.getAlgorithmInfo().bits, openpgp.config.minRSABits));
    });

    it('should throw when trying to add a new default subkey to an ecc key that uses a blacklisted curve (secp256k1)', async function() {
      const armoredSecp256k1Key = `-----BEGIN PGP PRIVATE KEY BLOCK-----

xXQEYxdOmhMFK4EEAAoCAwQ6I+bX7cpqyNxutHPNc8V6vTOPhjLfgjkGDkM4
/KcZeV4s/GFBzdBLMtIysvhvdRMxGVPVMM7G3FEpwC9E1WvuAAEAxvej4FiH
9nYJVM31f+rVPEprGJsfTmVRLtXe1PcwOzYQ/c0IVGVzdCBLZXnCjAQQEwgA
PgUCYxdOmgQLCQcICRCoxLkn4DOwYgMVCAoEFgACAQIZAQIbAwIeARYhBN37
7DwnrLsb5TBV2ajEuSfgM7BiAAAv0QD/YUjjQ9GK5F5UQRnN9C+5iqg+FVlv
Eei69w0jZHn97/gBAL7d1WmeOFqWEX06caukSHGrF3n86iVCyMqtw7Cq8Xv8
x3gEYxdOmhIFK4EEAAoCAwR361TPbl1Wzediq7fSAtTknv27qH2C47KcfAtt
+ngpp0DWfOaH507VcRpFA63wtRS1zLzJ6hY3yN/yuPm1AhbiAwEIBwAA/At9
ZrGc1PptXDDTUvL7scEZMlEDwXS8E4E27YIlsXkeELjCeAQYEwgAKgUCYxdO
mgkQqMS5J+AzsGICGwwWIQTd++w8J6y7G+UwVdmoxLkn4DOwYgAA2IoBAL9o
iBR1+Lfy6CES1sdCQC/Fy4p9SwHJ4D8a2t2J4Lr2AQCVjv7SWh70i3IAHddJ
XvmoLueOOShu01X/kaylMqaT8w==
=Dq/g
-----END PGP PRIVATE KEY BLOCK-----`;
      const key = await openpgp.readKey({ armoredKey: armoredSecp256k1Key });
      expect(key.subkeys).to.have.length(1);
      await expect(key.addSubkey()).to.be.rejectedWith(/Support for ecdh keys using curve secp256k1 is disabled/);
      expect(key.subkeys).to.have.length(1);

      // explicitly allow secp256k1 curve
      const config = { rejectCurves: new Set() };
      const newKey = await key.addSubkey({ config });
      expect(newKey.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh');
      expect(newKey.subkeys[0].getAlgorithmInfo().curve).to.equal('secp256k1');
    });

    it('should throw when trying to add a curve25519Legacy key to a v6 key', async function() {
      const v6Key = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----

xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMA
GXKBexK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJj
h3/jAwsJBwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifB
ilZwj2Ul7Ce62azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2
kCcUmKfvBXbAf6rhRYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaE
QsiPlR4zxP/TP7mhfVEe7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaT
JINn+eUBXbki+PSAld2nhJh/LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u
/tVY6a//1q0NWC1X+yui3O24wpsGGBsKAAAALAWCY4d/4wKbDCIhBssYbE8G
CaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce62azJAAAAAAQBIKbpGG2dWTX8j+Vj
FM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDEM0g12vYxoWM8Y81W+bHBw805
I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUrk0mXubZvyl4GBg==
-----END PGP PRIVATE KEY BLOCK-----` });
      expect(v6Key.subkeys).to.have.length(1);
      await expect(v6Key.addSubkey({ type: 'ecc' })).to.be.rejectedWith(/Cannot generate v6 keys of type 'ecc' with curve curve25519Legacy/);
      expect(v6Key.subkeys).to.have.length(1);
    });

    it('should throw when trying to encrypt a subkey separately from key', async function() {
      const privateKey = await openpgp.decryptKey({
        privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
        passphrase: 'hello world'
      });
      const opt = { rsaBits: rsaBits, passphrase: 'subkey passphrase' };
      await expect(privateKey.addSubkey(opt)).to.be.rejectedWith('Subkey could not be encrypted here, please encrypt whole key');
    });

    it('encrypt and decrypt key with added subkey', async function() {
      const privateKey = await openpgp.decryptKey({
        privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
        passphrase: 'hello world'
      });
      const total = privateKey.subkeys.length;

      const passphrase = '12345678';
      const newPrivateKey = await privateKey.addSubkey({ type: 'rsa' });
      const encNewPrivateKey = await openpgp.encryptKey({ privateKey: newPrivateKey, passphrase });
      expect(encNewPrivateKey.subkeys.length).to.be.equal(total + 1);

      const armoredKey = encNewPrivateKey.armor();
      const importedPrivateKey = await openpgp.decryptKey({
        privateKey: await openpgp.readKey({ armoredKey }),
        passphrase
      });
      const subkey = importedPrivateKey.subkeys[total];
      expect(subkey).to.exist;
      expect(importedPrivateKey.subkeys.length).to.be.equal(total + 1);
      await subkey.verify();
    });

    it('create and add a new eddsa subkey to a eddsa key', async function() {
      const passphrase = '12345678';
      const userID = { name: 'test', email: 'a@b.com' };
      const { privateKey } = await openpgp.generateKey({ curve: 'curve25519Legacy', userIDs: [userID], format: 'object', subkeys:[] });
      const total = privateKey.subkeys.length;

      let newPrivateKey = await privateKey.addSubkey({ curve: 'curve25519Legacy', userIDs: [userID], sign: true });
      const subkey1 = newPrivateKey.subkeys[total];
      const encNewPrivateKey = await openpgp.encryptKey({ privateKey: newPrivateKey, passphrase });
      newPrivateKey = await openpgp.decryptKey({
        privateKey: await openpgp.readKey({ armoredKey: encNewPrivateKey.armor() }),
        passphrase
      });
      const subkey2 = newPrivateKey.subkeys[total];
      expect(subkey2.isDecrypted()).to.be.true;
      expect(subkey1.getKeyID().toHex()).to.be.equal(subkey2.getKeyID().toHex());
      expect(subkey2).to.exist;
      expect(newPrivateKey.subkeys.length).to.be.equal(total + 1);
      const subkeyOid = subkey2.keyPacket.publicParams.oid;
      const pkOid = privateKey.keyPacket.publicParams.oid;
      expect(subkeyOid.getName()).to.be.equal(pkOid.getName());
      expect(subkey2.getAlgorithmInfo().algorithm).to.be.equal('eddsaLegacy');
      await subkey2.verify();
      expect(await newPrivateKey.getSigningKey()).to.be.equal(subkey2);
    });

    it('create and add a new ecdsa subkey to a eddsa key (equal timestamp)', async function() {
      const userID = { name: 'test', email: 'a@b.com' };
      const { privateKey } = await openpgp.generateKey({ curve: 'ed25519Legacy', userIDs: [userID], format: 'object', subkeys: [{ sign: true }] });
      const total = privateKey.subkeys.length;
      let newPrivateKey = await privateKey.addSubkey({ curve: 'nistP256', sign: true, date: privateKey.subkeys[0].getCreationTime() });
      newPrivateKey = await openpgp.readKey({ armoredKey: newPrivateKey.armor() });
      const subkey = newPrivateKey.subkeys[total];
      expect(subkey).to.exist;
      expect(newPrivateKey.subkeys.length).to.be.equal(total + 1);
      expect(newPrivateKey.getAlgorithmInfo().curve).to.be.equal('ed25519Legacy');
      expect(subkey.getAlgorithmInfo().curve).to.be.equal('nistP256');
      expect(newPrivateKey.getAlgorithmInfo().algorithm).to.be.equal('eddsaLegacy');
      expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('ecdsa');
      await subkey.verify();
      expect(await newPrivateKey.getSigningKey()).to.be.equal(newPrivateKey.subkeys[0]);
    });

    it('create and add a new ecdsa subkey to a eddsa key (later timestamp)', async function() {
      const userID = { name: 'test', email: 'a@b.com' };
      const { privateKey } = await openpgp.generateKey({ curve: 'ed25519Legacy', userIDs: [userID], format: 'object', subkeys: [{ sign: true }] });
      const total = privateKey.subkeys.length;
      let newPrivateKey = await privateKey.addSubkey({ curve: 'nistP256', sign: true, date: new Date(+privateKey.subkeys[0].getCreationTime() + 1000) });
      newPrivateKey = await openpgp.readKey({ armoredKey: newPrivateKey.armor() });
      const subkey = newPrivateKey.subkeys[total];
      expect(subkey).to.exist;
      expect(newPrivateKey.subkeys.length).to.be.equal(total + 1);
      expect(newPrivateKey.getAlgorithmInfo().curve).to.be.equal('ed25519Legacy');
      expect(subkey.getAlgorithmInfo().curve).to.be.equal('nistP256');
      expect(newPrivateKey.getAlgorithmInfo().algorithm).to.be.equal('eddsaLegacy');
      expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('ecdsa');
      await subkey.verify(new Date(+privateKey.subkeys[0].getCreationTime() + 1000));
      expect(await newPrivateKey.getSigningKey(undefined, new Date(+privateKey.subkeys[0].getCreationTime() + 1000))).to.be.equal(subkey);
    });

    it('create and add a new ecc subkey to a rsa key (equal timestamp)', async function() {
      const privateKey = await openpgp.decryptKey({
        privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
        passphrase: 'hello world'
      });
      const total = privateKey.subkeys.length;
      const opt2 = { type: 'ecc', curve: 'curve25519', date: privateKey.subkeys[0].getCreationTime() };
      let newPrivateKey = await privateKey.addSubkey(opt2);
      const armoredKey = newPrivateKey.armor();
      newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey });
      expect(newPrivateKey.subkeys.length).to.be.equal(total + 1);
      const subkey = newPrivateKey.subkeys[total];
      expect(subkey).to.exist;
      expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('ecdh');
      expect(subkey.getAlgorithmInfo().curve).to.be.equal(openpgp.enums.curve.curve25519Legacy);
      await subkey.verify();
      expect(await newPrivateKey.getEncryptionKey()).to.be.equal(subkey);
    });

    it('create and add a new ecc subkey to a rsa key (later timestamp)', async function() {
      const privateKey = await openpgp.decryptKey({
        privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
        passphrase: 'hello world'
      });
      const total = privateKey.subkeys.length;
      const opt2 = { type: 'ecc', curve: 'curve25519' };
      let newPrivateKey = await privateKey.addSubkey(opt2);
      const armoredKey = newPrivateKey.armor();
      newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey });
      expect(newPrivateKey.subkeys.length).to.be.equal(total + 1);
      const subkey = newPrivateKey.subkeys[total];
      expect(subkey).to.exist;
      expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('ecdh');
      expect(subkey.getAlgorithmInfo().curve).to.be.equal(openpgp.enums.curve.curve25519Legacy);
      await subkey.verify();
      expect(await newPrivateKey.getEncryptionKey()).to.be.equal(subkey);
    });

    it('create and add a new rsa subkey to a ecc key (equal timestamp)', async function() {
      const userID = { name: 'test', email: 'a@b.com' };
      const opt = { curve: 'ed25519Legacy', userIDs: [userID], format: 'object' };
      const { privateKey } = await openpgp.generateKey(opt);
      const total = privateKey.subkeys.length;
      let newPrivateKey = await privateKey.addSubkey({ type: 'rsa', date: privateKey.subkeys[0].getCreationTime() });
      const armoredKey = newPrivateKey.armor();
      newPrivateKey = await openpgp.readKey({ armoredKey });
      const subkey = newPrivateKey.subkeys[total];
      expect(subkey).to.exist;
      expect(newPrivateKey.subkeys.length).to.be.equal(total + 1);
      expect(subkey.getAlgorithmInfo().bits).to.be.equal(4096);
      expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('rsaEncryptSign');
      await subkey.verify();
      expect(await newPrivateKey.getEncryptionKey()).to.be.equal(newPrivateKey.subkeys[0]);
    });

    it('create and add a new rsa subkey to a ecc key (later timestamp)', async function() {
      const userID = { name: 'test', email: 'a@b.com' };
      const opt = { curve: 'ed25519Legacy', userIDs: [userID], format: 'object' };
      const { privateKey } = await openpgp.generateKey(opt);
      const total = privateKey.subkeys.length;
      let newPrivateKey = await privateKey.addSubkey({ type: 'rsa', date: new Date(+privateKey.subkeys[0].getCreationTime() + 1000) });
      const armoredKey = newPrivateKey.armor();
      newPrivateKey = await openpgp.readKey({ armoredKey });
      const subkey = newPrivateKey.subkeys[total];
      expect(subkey).to.exist;
      expect(newPrivateKey.subkeys.length).to.be.equal(total + 1);
      expect(subkey.getAlgorithmInfo().bits).to.be.equal(4096);
      expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('rsaEncryptSign');
      await subkey.verify(new Date(+privateKey.subkeys[0].getCreationTime() + 1000));
      expect(await newPrivateKey.getEncryptionKey(undefined, new Date(+privateKey.subkeys[0].getCreationTime() + 1000))).to.be.equal(subkey);
    });

    it('create and add a new rsa subkey to a dsa key', async function() {
      const privateKey = await openpgp.readKey({ armoredKey: dsaPrivateKey });
      const total = privateKey.subkeys.length;
      let newPrivateKey = await privateKey.addSubkey({ type: 'rsa', rsaBits: 2048 });
      newPrivateKey = await openpgp.readKey({ armoredKey: newPrivateKey.armor() });
      expect(newPrivateKey.subkeys.length).to.be.equal(total + 1);
      const subkey = newPrivateKey.subkeys[total];
      expect(subkey).to.exist;
      expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('rsaEncryptSign');
      expect(subkey.getAlgorithmInfo().bits).to.be.equal(2048);
      await subkey.verify();
      expect(await newPrivateKey.getEncryptionKey(undefined, undefined, undefined, { ...openpgp.config, rejectPublicKeyAlgorithms: new Set() })).to.be.equal(subkey);
    });

    it('sign/verify data with the new subkey correctly using curve25519 (legacy format)', async function() {
      const userID = { name: 'test', email: 'a@b.com' };
      const opt = { curve: 'curve25519', userIDs: [userID], format: 'object', subkeys:[] };
      const { privateKey } = await openpgp.generateKey(opt);

      const total = privateKey.subkeys.length;
      const opt2 = { sign: true };
      let newPrivateKey = await privateKey.addSubkey(opt2);
      const armoredKey = newPrivateKey.armor();
      newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey });

      const subkey = newPrivateKey.subkeys[total];
      const subkeyOid = subkey.keyPacket.publicParams.oid;
      const pkOid = newPrivateKey.keyPacket.publicParams.oid;
      expect(subkeyOid.getName()).to.be.equal(pkOid.getName());
      expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('eddsaLegacy');
      await subkey.verify();
      expect(await newPrivateKey.getSigningKey()).to.be.equal(subkey);
      const signed = await openpgp.sign({ message: await openpgp.createMessage({ text: 'the data to signed' }), signingKeys: newPrivateKey, format: 'binary' });
      const message = await openpgp.readMessage({ binaryMessage: signed });
      const { signatures } = await openpgp.verify({ message, verificationKeys: [newPrivateKey.toPublic()] });
      expect(signatures).to.exist;
      expect(signatures.length).to.be.equal(1);
      expect(signatures[0].keyID.toHex()).to.be.equal(subkey.getKeyID().toHex());
      expect(await signatures[0].verified).to.be.true;
    });

    it('encrypt/decrypt data with the new subkey correctly using curve25519 (legacy format)', async function() {
      const userID = { name: 'test', email: 'a@b.com' };
      const vData = 'the data to encrypted!';
      const opt = { curve: 'curve25519', userIDs: [userID], format: 'object', subkeys:[] };
      const { privateKey } = await openpgp.generateKey(opt);
      const total = privateKey.subkeys.length;
      let newPrivateKey = await privateKey.addSubkey();
      const armoredKey = newPrivateKey.armor();
      newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey });
      const subkey = newPrivateKey.subkeys[total];
      const publicKey = newPrivateKey.toPublic();
      await subkey.verify();
      expect(await newPrivateKey.getEncryptionKey()).to.be.equal(subkey);
      const encrypted = await openpgp.encrypt({ message: await openpgp.createMessage({ text: vData }), encryptionKeys: publicKey, format: 'binary' });
      expect(encrypted).to.be.exist;
      const message = await openpgp.readMessage({ binaryMessage: encrypted });
      const pkSessionKeys = message.packets.filterByTag(openpgp.enums.packet.publicKeyEncryptedSessionKey);
      expect(pkSessionKeys).to.exist;
      expect(pkSessionKeys.length).to.be.equal(1);
      expect(pkSessionKeys[0].publicKeyID.toHex()).to.be.equals(subkey.keyPacket.getKeyID().toHex());
      const decrypted = await openpgp.decrypt({ message, decryptionKeys: newPrivateKey });
      expect(decrypted).to.exist;
      expect(decrypted.data).to.be.equal(vData);
    });

    ['curve25519', 'curve448'].forEach(keyType => (
      it(`encrypt/decrypt data with the new subkey correctly using ${keyType}`, async function() {
        const userID = { name: 'test', email: 'a@b.com' };
        const vData = 'the data to encrypted!';
        const opt = { type: keyType, userIDs: [userID], format: 'object', subkeys:[] };
        const { privateKey } = await openpgp.generateKey(opt);
        const total = privateKey.subkeys.length;
        let newPrivateKey = await privateKey.addSubkey();
        const armoredKey = newPrivateKey.armor();
        newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey });
        const subkey = newPrivateKey.subkeys[total];
        const publicKey = newPrivateKey.toPublic();
        await subkey.verify();
        expect(await newPrivateKey.getEncryptionKey()).to.be.equal(subkey);
        const encrypted = await openpgp.encrypt({ message: await openpgp.createMessage({ text: vData }), encryptionKeys: publicKey, format: 'binary' });
        expect(encrypted).to.be.exist;
        const message = await openpgp.readMessage({ binaryMessage: encrypted });
        const pkSessionKeys = message.packets.filterByTag(openpgp.enums.packet.publicKeyEncryptedSessionKey);
        expect(pkSessionKeys).to.exist;
        expect(pkSessionKeys.length).to.be.equal(1);
        expect(pkSessionKeys[0].publicKeyID.toHex()).to.be.equals(subkey.keyPacket.getKeyID().toHex());
        const decrypted = await openpgp.decrypt({ message, decryptionKeys: newPrivateKey });
        expect(decrypted).to.exist;
        expect(decrypted.data).to.be.equal(vData);
      })
    ));

    it('sign/verify data with the new subkey correctly using rsa', async function() {
      const privateKey = await openpgp.decryptKey({
        privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
        passphrase: 'hello world'
      });
      const total = privateKey.subkeys.length;
      const opt2 = { sign: true, rsaBits: rsaBits };
      let newPrivateKey = await privateKey.addSubkey(opt2);
      const armoredKey = newPrivateKey.armor();
      newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey });

      const subkey = newPrivateKey.subkeys[total];
      expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('rsaEncryptSign');
      await subkey.verify();
      expect(await newPrivateKey.getSigningKey()).to.be.equal(subkey);
      const signed = await openpgp.sign({ message: await openpgp.createMessage({ text: 'the data to signed' }), signingKeys: newPrivateKey, format: 'binary' });
      const message = await openpgp.readMessage({ binaryMessage: signed });
      const { signatures } = await openpgp.verify({ message, verificationKeys: [newPrivateKey.toPublic()] });
      expect(signatures).to.exist;
      expect(signatures.length).to.be.equal(1);
      expect(signatures[0].keyID.toHex()).to.be.equal(subkey.getKeyID().toHex());
      expect(await signatures[0].verified).to.be.true;
    });

    it('encrypt/decrypt data with the new subkey correctly using rsa', async function() {
      const privateKey = await openpgp.decryptKey({
        privateKey: await openpgp.readKey({ armoredKey: priv_key_rsa }),
        passphrase: 'hello world'
      });
      const total = privateKey.subkeys.length;
      let newPrivateKey = await privateKey.addSubkey({ type: 'rsa' });
      const armoredKey = newPrivateKey.armor();
      newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey });

      const subkey = newPrivateKey.subkeys[total];
      const publicKey = newPrivateKey.toPublic();
      const vData = 'the data to encrypted!';
      expect(await newPrivateKey.getEncryptionKey()).to.be.equal(subkey);
      const encrypted = await openpgp.encrypt({ message: await openpgp.createMessage({ text: vData }), encryptionKeys: publicKey, format: 'binary' });
      expect(encrypted).to.be.exist;
      const message = await openpgp.readMessage({ binaryMessage: encrypted });
      const pkSessionKeys = message.packets.filterByTag(openpgp.enums.packet.publicKeyEncryptedSessionKey);
      expect(pkSessionKeys).to.exist;
      expect(pkSessionKeys.length).to.be.equal(1);
      expect(pkSessionKeys[0].publicKeyID.toHex()).to.be.equals(subkey.keyPacket.getKeyID().toHex());
      const decrypted = await openpgp.decrypt({ message, decryptionKeys: newPrivateKey });
      expect(decrypted).to.exist;
      expect(decrypted.data).to.be.equal(vData);
    });
  });

  it('Subkey.verify returns the latest valid signature', async function () {
    const { privateKey: encryptionKey } = await openpgp.generateKey({ userIDs: { name: 'purple' }, format: 'object' });
    const encryptionKeySignature = await encryptionKey.getSubkeys()[0].verify();
    expect(encryptionKeySignature instanceof openpgp.SignaturePacket).to.be.true;
    expect(encryptionKeySignature.keyFlags[0] & openpgp.enums.keyFlags.encryptCommunication).to.be.equals(openpgp.enums.keyFlags.encryptCommunication);
    expect(encryptionKeySignature.keyFlags[0] & openpgp.enums.keyFlags.encryptStorage).to.be.equals(openpgp.enums.keyFlags.encryptStorage);

    const { privateKey: signingKey } = await openpgp.generateKey({ userIDs: { name: 'purple' }, format: 'object', subkeys: [{ sign: true }] });
    const signingKeySignature = await signingKey.getSubkeys()[0].verify();
    expect(signingKeySignature instanceof openpgp.SignaturePacket).to.be.true;
    expect(signingKeySignature.keyFlags[0] & openpgp.enums.keyFlags.signData).to.be.equals(openpgp.enums.keyFlags.signData);
  });
});
